The content model of p
allows only “inline” or “text-level” content. The exact content model (and terminology) varies by HTML version, but no version regards h2
as inline/text-level. See e.g. HTML 4.01 spec text on the p
element. The requirement is rather natural if you think of p
in its old meaning in HTML: it marks up a paragraph of text. It’s basically a block of copy text.
The content model is enforced by browsers, by parsing rules: when a p
element is open, an <h2>
tag implicitly closes it. So in the case given in the question, the td
element contains a p
element with just whitespace as content, then an h2
element, and then “loose” text (just a text node).
The conclusions depend on your reasons for wanting to wrap the cell content in a p
element. Normally, there is no reason to that. But if you need a wrapper, use the div
element instead.