diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
index dc95a9dc643..98f5019a03d 100644
--- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
@@ -447,6 +447,42 @@ describe('resolveType', () => {
     })
   })
 
+  test('keyof', () => {
+    const files = {
+      '/foo.ts': `export type IMP = { ${1}: 1 };`,
+    }
+
+    const { props } = resolve(
+      `
+      import { IMP } from './foo'
+      interface Foo { foo: 1, ${1}: 1 } 
+      type Bar = { bar: 1 }
+      declare const obj: Bar
+      declare const set: Set<any>
+      declare const arr: Array<any>
+
+      defineProps<{ 
+        imp: keyof IMP,
+        foo: keyof Foo,
+        bar: keyof Bar,
+        obj: keyof typeof obj,
+        set: keyof typeof set,
+        arr: keyof typeof arr
+      }>()
+      `,
+      files,
+    )
+
+    expect(props).toStrictEqual({
+      imp: ['Number'],
+      foo: ['String', 'Number'],
+      bar: ['String'],
+      obj: ['String'],
+      set: ['String'],
+      arr: ['String', 'Number'],
+    })
+  })
+
   test('ExtractPropTypes (element-plus)', () => {
     const { props, raw } = resolve(
       `
diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts
index 54b207e7e91..bbed11baffe 100644
--- a/packages/compiler-sfc/src/script/resolveType.ts
+++ b/packages/compiler-sfc/src/script/resolveType.ts
@@ -1448,6 +1448,7 @@ export function inferRuntimeType(
   ctx: TypeResolveContext,
   node: Node & MaybeWithScope,
   scope = node._ownerScope || ctxToScope(ctx),
+  isKeyOf = false,
 ): string[] {
   try {
     switch (node.type) {
@@ -1467,8 +1468,18 @@ export function inferRuntimeType(
         const types = new Set<string>()
         const members =
           node.type === 'TSTypeLiteral' ? node.members : node.body.body
+
         for (const m of members) {
-          if (
+          if (isKeyOf) {
+            if (
+              m.type === 'TSPropertySignature' &&
+              m.key.type === 'NumericLiteral'
+            ) {
+              types.add('Number')
+            } else {
+              types.add('String')
+            }
+          } else if (
             m.type === 'TSCallSignatureDeclaration' ||
             m.type === 'TSConstructSignatureDeclaration'
           ) {
@@ -1477,6 +1488,7 @@ export function inferRuntimeType(
             types.add('Object')
           }
         }
+
         return types.size ? Array.from(types) : ['Object']
       }
       case 'TSPropertySignature':
@@ -1512,9 +1524,22 @@ export function inferRuntimeType(
       case 'TSTypeReference': {
         const resolved = resolveTypeReference(ctx, node, scope)
         if (resolved) {
-          return inferRuntimeType(ctx, resolved, resolved._ownerScope)
+          return inferRuntimeType(ctx, resolved, resolved._ownerScope, isKeyOf)
         }
+
         if (node.typeName.type === 'Identifier') {
+          if (isKeyOf) {
+            switch (node.typeName.name) {
+              case 'String':
+              case 'Array':
+              case 'ArrayLike':
+              case 'ReadonlyArray':
+                return ['String', 'Number']
+              default:
+                return ['String']
+            }
+          }
+
           switch (node.typeName.name) {
             case 'Array':
             case 'Function':
@@ -1634,7 +1659,7 @@ export function inferRuntimeType(
           // typeof only support identifier in local scope
           const matched = scope.declares[id.name]
           if (matched) {
-            return inferRuntimeType(ctx, matched, matched._ownerScope)
+            return inferRuntimeType(ctx, matched, matched._ownerScope, isKeyOf)
           }
         }
         break
@@ -1642,7 +1667,12 @@ export function inferRuntimeType(
 
       // e.g. readonly
       case 'TSTypeOperator': {
-        return inferRuntimeType(ctx, node.typeAnnotation, scope)
+        return inferRuntimeType(
+          ctx,
+          node.typeAnnotation,
+          scope,
+          node.operator === 'keyof',
+        )
       }
     }
   } catch (e) {