{"record":{"id":"26f83430d76c3814","repo":"dotnet/efcore","slug":"the-foreign-keys-foreignkeyproperties1-on-enti-26f834","errorCode":null,"errorMessage":"The foreign keys {foreignKeyProperties1} on '{entityType1}' and {foreignKeyProperties2} on '{entityType2}' are both mapped to '{table}.{foreignKeyName}', but referencing different principal columns ({principalColumnNames1} and {principalColumnNames2}).","messagePattern":"The foreign keys (.+?) on '(.+?)' and (.+?) on '(.+?)' are both mapped to '(.+?)\\.(.+?)', but referencing different principal columns \\((.+?) and (.+?)\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs","lineNumber":101,"sourceCode":"        {\n            return shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateForeignKeyColumnMismatch(\n                        foreignKey.Properties.Format(),\n                        foreignKey.DeclaringEntityType.DisplayName(),\n                        duplicateForeignKey.Properties.Format(),\n                        duplicateForeignKey.DeclaringEntityType.DisplayName(),\n                        foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),\n                        foreignKey.GetConstraintName(storeObject, principalTable.Value),\n                        foreignKey.Properties.FormatColumns(storeObject),\n                        duplicateForeignKey.Properties.FormatColumns(storeObject)))\n                : false;\n        }\n\n        if (!principalColumns.SequenceEqual(duplicatePrincipalColumns))\n        {\n            return shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateForeignKeyPrincipalColumnMismatch(\n                        foreignKey.Properties.Format(),\n                        foreignKey.DeclaringEntityType.DisplayName(),\n                        duplicateForeignKey.Properties.Format(),\n                        duplicateForeignKey.DeclaringEntityType.DisplayName(),\n                        foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),\n                        foreignKey.GetConstraintName(storeObject, principalTable.Value),\n                        foreignKey.PrincipalKey.Properties.FormatColumns(principalTable.Value),\n                        duplicateForeignKey.PrincipalKey.Properties.FormatColumns(principalTable.Value)))\n                : false;\n        }\n\n        if (foreignKey.IsUnique != duplicateForeignKey.IsUnique)\n        {\n            return shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateForeignKeyUniquenessMismatch(\n                        foreignKey.Properties.Format(),","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs#L83-L119","documentation":"Thrown during relational model finalization when two foreign keys resolve to the same constraint name on the same table but their principal key properties map to different principal columns. EF requires every constraint sharing a name to be byte-for-byte identical so that migrations emit a single, unambiguous constraint.","triggerScenarios":"RelationalForeignKeyExtensions.AreCompatible(foreignKey, duplicateForeignKey, storeObject, shouldThrow: true) when !principalColumns.SequenceEqual(duplicatePrincipalColumns). Happens when two entities share a table (TPT/TPH/splitting) and their FKs land on the same constraint name while pointing at different principal key columns (e.g. one targets PK.Id, another targets an alternate key on a different column).","commonSituations":"TPT inheritance where derived entities define FKs that collapse to the same default constraint name; table-splitting where the same principal is referenced through different keys; manual HasConstraintName calls that collide; upgrade from a version that did not validate this to one that does.","solutions":["Inspect the constraint name in the message and give the two FKs distinct names via HasConstraintName(...) so they no longer collide.","Align both FKs to reference the same principal key (same PrincipalKey) so the principal columns match.","If the duplication is intentional (e.g. table-splitting), remap one FK to a different column set or remove the redundant FK.","Use ToTable/ToView to separate the entities onto different tables so their constraints do not share a name."],"exampleFix":"// before: both FKs default to the same constraint name but target different principal columns\nmodelBuilder.Entity<Order>().HasOne(o => o.Customer).WithMany().HasForeignKey(o => o.CustomerId);\nmodelBuilder.Entity<Invoice>().HasOne(i => i.Customer).WithMany().HasForeignKey(i => o.CustomerAltId);\n\n// after: give them explicit, distinct constraint names\nmodelBuilder.Entity<Order>().HasOne(o => o.Customer).WithMany().HasForeignKey(o => o.CustomerId)\n    .HasConstraintName(\"FK_Order_Customer_Id\");\nmodelBuilder.Entity<Invoice>().HasOne(i => i.Customer).WithMany().HasForeignKey(i => i.CustomerAltId)\n    .HasConstraintName(\"FK_Invoice_Customer_AltId\");","handlingStrategy":"validation","validationCode":"// Before finalizing the model, ensure colliding FKs share principal columns.\nforeach (var entityType in modelBuilder.Model.GetEntityTypes())\n{\n    foreach (var fk in entityType.GetForeignKeys())\n    {\n        var name = fk.GetConstraintName();\n        var dupes = modelBuilder.Model.GetEntityTypes()\n            .SelectMany(e => e.GetForeignKeys())\n            .Where(o => o != fk && o.GetConstraintName() == name)\n            .ToList();\n        foreach (var dup in dupes)\n        {\n            if (!fk.PrincipalKey.Properties.SequenceEqual(dup.PrincipalKey.Properties))\n                Console.WriteLine($\"FK constraint name '{name}' collides with different principal columns.\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set explicit HasConstraintName for FKs in TPT/splitting scenarios to avoid accidental name collisions.","Run model validation in a unit test (modelBuilder.FinalizeModel()) as part of CI.","Keep one relationship per (principal, dependent) pair unless you intentionally differentiate via constraint names."],"tags":["ef-core","relational-metadata","foreign-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"}