{"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/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs#L15-L51","documentation":"Two keys share the same database name but their declaring entities are mapped to different tables, so at least one cannot produce a column list for the store object. One key constraint name cannot span two tables.","triggerScenarios":"RelationalKeyExtensions.AreCompatible with shouldThrow:true when key.Properties.GetColumnNames(storeObject) or duplicateKey.Properties.GetColumnNames(storeObject) returns null. Common in TPT/Tpc inheritance where the same key constraint name is reused across the base and derived tables.","commonSituations":"TPT hierarchies with default key naming; explicit HasKeyName reuse across entities mapped to different tables; switching mapping strategies without renaming constraints.","solutions":["Give each key a distinct name via HasName(...) on the key.","Ensure both keys are mapped to the same table if the shared name is intentional.","Remove the redundant key definition.","When changing inheritance strategy, regenerate constraint names."],"exampleFix":"// before: TPT, both default to 'PK_Base'\nmodelBuilder.Entity<Base>().ToTable(\"Base\").HasKey(b => b.Id);\nmodelBuilder.Entity<Derived>().ToTable(\"Derived\").HasKey(d => d.Id);\n\n// after: rename one\nmodelBuilder.Entity<Derived>().ToTable(\"Derived\").HasKey(d => d.Id).HasName(\"PK_Derived\");","handlingStrategy":"validation","validationCode":"// Find keys whose names collide across different tables.\nvar keys = modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetDeclaredKeys());\nforeach (var k in keys)\n{\n    var name = k.GetName();\n    foreach (var dup in keys.Where(o => o != k && o.GetName() == name\n                                       && o.DeclaringEntityType.GetSchemaQualifiedTableName() != k.DeclaringEntityType.GetSchemaQualifiedTableName()))\n    {\n        Console.WriteLine($\"Key name '{name}' used on two tables: {k.DeclaringEntityType.Name} and {dup.DeclaringEntityType.Name}.\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set explicit HasName for keys in TPT/Tpc hierarchies.","After switching inheritance strategies, regenerate key constraint names.","Add a model validation test to CI."],"tags":["ef-core","relational-metadata","key","model-validation","tpt"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}