diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index b7a996c29ca2..3092f3bc11ed 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1851,6 +1851,26 @@ def check_issue10777():
>>> ET.register_namespace('test10777', 'http://myuri/')
"""
+def check_html_empty_elems_serialization(self):
+ # issue 15970
+ # from http://www.w3.org/TR/html401/index/elements.html
+ """
+
+ >>> empty_elems = ['AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME', 'HR',
+ ... 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM']
+ >>> elems = ''.join('<%s />' % elem for elem in empty_elems)
+ >>> serialize(ET.XML('%s' % elems), method='html')
+ '
'
+ >>> serialize(ET.XML('%s' % elems.lower()), method='html')
+ '
'
+ >>> elems = ''.join('<%s>%s>' % (elem, elem) for elem in empty_elems)
+ >>> serialize(ET.XML('%s' % elems), method='html')
+ '
'
+ >>> serialize(ET.XML('%s' % elems.lower()), method='html')
+ '
'
+
+ """
+
# --------------------------------------------------------------------
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index f94c48c09c7d..9742f32f3810 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -983,7 +983,7 @@ def _serialize_xml(write, elem, qnames, namespaces):
write(_escape_cdata(elem.tail))
HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
- "img", "input", "isindex", "link", "meta" "param")
+ "img", "input", "isindex", "link", "meta", "param")
try:
HTML_EMPTY = set(HTML_EMPTY)
diff --git a/Misc/NEWS b/Misc/NEWS
index 29e2c1956562..5113ec08ce99 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -120,6 +120,9 @@ Core and Builtins
Library
-------
+- Issue #15970: xml.etree.ElementTree now serializes correctly the empty HTML
+ elements 'meta' and 'param'.
+
- Issue #15842: the SocketIO.{readable,writable,seekable} methods now
raise ValueError when the file-like object is closed. Patch by Alessandro
Moura.