diff --git a/packages/runtime-core/__tests__/rendererChildren.spec.ts b/packages/runtime-core/__tests__/rendererChildren.spec.ts
index 47024b674f4..2c3e5ff0d1a 100644
--- a/packages/runtime-core/__tests__/rendererChildren.spec.ts
+++ b/packages/runtime-core/__tests__/rendererChildren.spec.ts
@@ -65,6 +65,15 @@ test('array children -> text children', () => {
expect(inner(root)).toBe('
hello
')
})
+test('plain object child', () => {
+ const root = nodeOps.createElement('div')
+ const foo = { foo: '1' }
+ // @ts-expect-error
+ render(h('div', null, [foo]), root)
+ expect('Invalid VNode type').not.toHaveBeenWarned()
+ expect(inner(root)).toBe('[object Object]
')
+})
+
describe('renderer: keyed children', () => {
let root: TestElement
let elm: TestElement
diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts
index 57c0cf8b7d2..30200789be8 100644
--- a/packages/runtime-core/src/vnode.ts
+++ b/packages/runtime-core/src/vnode.ts
@@ -793,7 +793,7 @@ export function normalizeVNode(child: VNodeChild): VNode {
// #3666, avoid reference pollution when reusing vnode
child.slice(),
)
- } else if (typeof child === 'object') {
+ } else if (isVNode(child)) {
// already vnode, this should be the most common since compiled templates
// always produce all-vnode children arrays
return cloneIfMounted(child)