{"record":{"id":"1ccc47234be4777d","repo":"dotnet/efcore","slug":"the-keys-keyproperties1-on-entitytype1-and","errorCode":null,"errorMessage":"The keys {keyProperties1} on '{entityType1}' and {keyProperties2} on '{entityType2}' are both mapped to '{keyName}', but on different tables ('{table1}' and '{table2}').","messagePattern":"The keys (.+?) on '(.+?)' and (.+?) on '(.+?)' are both mapped to '(.+?)', but on different tables \\('(.+?)' and '(.+?)'\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs","lineNumber":33,"sourceCode":"{\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public static bool AreCompatible(\n        this IReadOnlyKey key,\n        IReadOnlyKey duplicateKey,\n        in StoreObjectIdentifier storeObject,\n        bool shouldThrow)\n    {\n        var columnNames = key.Properties.GetColumnNames(storeObject);\n        var duplicateColumnNames = duplicateKey.Properties.GetColumnNames(storeObject);\n        return columnNames == null\n            || duplicateColumnNames == null\n                ? shouldThrow\n                    ? throw new InvalidOperationException(\n                        RelationalStrings.DuplicateKeyTableMismatch(\n                            key.Properties.Format(),\n                            key.DeclaringEntityType.DisplayName(),\n                            duplicateKey.Properties.Format(),\n                            duplicateKey.DeclaringEntityType.DisplayName(),\n                            key.GetName(storeObject),\n                            key.DeclaringEntityType.GetSchemaQualifiedTableName(),\n                            duplicateKey.DeclaringEntityType.GetSchemaQualifiedTableName()))\n                    : false\n                : columnNames.SequenceEqual(duplicateColumnNames)\n                || (shouldThrow\n                    ? throw new InvalidOperationException(\n                        RelationalStrings.DuplicateKeyColumnMismatch(\n                            key.Properties.Format(),\n                            key.DeclaringEntityType.DisplayName(),\n                            duplicateKey.Properties.Format(),\n                            duplicateKey.DeclaringEntityType.DisplayName(),\n                            key.DeclaringEntityType.GetSchemaQualifiedTableName(),","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs#L15-L51","documentation":"Thrown by RelationalKeyExtensions.AreCompatible during model validation when two keys (PK or alternate) share the same key name but key.Properties.GetColumnNames(storeObject) returns null for at least one — meaning the key's properties do not resolve to columns on the store object the duplicate lives on. EF treats same-named keys as one physical constraint, so it refuses keys that do not share one concrete column set on one table.","triggerScenarios":"Lines 30-42 of RelationalKeyExtensions.cs: columnNames == null || duplicateColumnNames == null. Produced when HasKey/HasAlternateKey with GetName(storeObject) collides across entity types whose properties are not mapped to columns on the shared table (e.g. JSON-mapped entities at line 109, or TPT table mismatches).","commonSituations":"Two entity types configured with the same key name via the Name annotation but mapped to different tables; an entity mapped to JSON getting a key whose name collides with a table-mapped entity's key; TPT inheritance where a key name is reused across hierarchy tables.","solutions":["Rename one key so each table/constraint has a distinct name, or remove the explicit key-name override.","Ensure both entity types actually share the same table and that every key property resolves to a column on it (avoid JSON mapping for the colliding key).","If one entity is JSON-mapped, do not give its key the same name as a table-mapped entity's key.","Inspect key.Properties.GetColumnNames(storeObject) on both keys to see which returns null and why."],"exampleFix":"// before\nmodelBuilder.Entity<Tenant>().HasAlternateKey(t => t.Code).HasName(\"AK_Code\");\nmodelBuilder.Entity<Region>().HasAlternateKey(r => r.Code).HasName(\"AK_Code\"); // different tables -> throws\n\n// after\nmodelBuilder.Entity<Region>().HasAlternateKey(r => r.Code).HasName(\"AK_Region_Code\");","handlingStrategy":"validation","validationCode":"// Ensure each named key resolves columns on a single table\nforeach (var et in model.GetEntityTypes())\n{\n    foreach (var key in et.GetDeclaredKeys())\n    {\n        foreach (var mapping in et.GetTableMappings())\n        {\n            var so = StoreObjectIdentifier.Table(mapping.Table.Name, mapping.Table.Schema);\n            if (key.GetName(so) is string n\n                && key.Properties.GetColumnNames(so) is null)\n            {\n                throw new InvalidOperationException($\"Key '{n}' on {et.Name} does not resolve to columns on {so.DisplayName()}\");\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not reuse key names across entity types on different tables.","Avoid naming JSON-mapped entity keys the same as table-mapped entity keys.","Add a model-validation test asserting no DuplicateKey* conflicts."],"tags":["relational","model-validation","key","table-mapping"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}