{"record":{"id":"86f1220ceb3cd98f","repo":"dotnet/efcore","slug":"the-foreign-keys-foreignkeyproperties1-on-enti-86f122","errorCode":null,"errorMessage":"The foreign keys {foreignKeyProperties1} on '{entityType1}' and {foreignKeyProperties2} on '{entityType2}' are both mapped to '{table}.{foreignKeyName}', but configured with different delete behavior ('{deleteBehavior1}' and '{deleteBehavior2}').","messagePattern":"The foreign keys (.+?) on '(.+?)' and (.+?) on '(.+?)' are both mapped to '(.+?)\\.(.+?)', but configured with different delete behavior \\('(.+?)' and '(.+?)'\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs","lineNumber":132,"sourceCode":"        if (foreignKey.IsUnique != duplicateForeignKey.IsUnique)\n        {\n            return shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateForeignKeyUniquenessMismatch(\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                : false;\n        }\n\n        var referentialAction = RelationalModel.ToReferentialAction(foreignKey.DeleteBehavior);\n        var duplicateReferentialAction = RelationalModel.ToReferentialAction(duplicateForeignKey.DeleteBehavior);\n        return referentialAction != duplicateReferentialAction\n            ? shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateForeignKeyDeleteBehaviorMismatch(\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                        referentialAction,\n                        duplicateReferentialAction))\n                : false\n            : foreignKey.IsExcludedFromMigrations() == duplicateForeignKey.IsExcludedFromMigrations()\n            || (shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateForeignKeyExcludedFromMigrationsMismatch(\n                        foreignKey.Properties.Format(),\n                        foreignKey.DeclaringEntityType.DisplayName(),\n                        duplicateForeignKey.Properties.Format(),\n                        duplicateForeignKey.DeclaringEntityType.DisplayName(),","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs#L114-L150","documentation":"Thrown by AreCompatible when two foreign keys share name and all column/table configuration but specify different DeleteBehavior that maps to different referential actions. A single FK constraint can carry only one ON DELETE action, so conflicting actions (e.g. Cascade vs Restrict) cannot be merged.","triggerScenarios":"Two sharing-table FKs with the same constraint name but different OnDelete(...) values whose ReferentialAction mappings differ (Cascade vs SetNull vs Restrict vs NoAction). Note: behaviors that map to the same action (e.g. Restrict and NoAction both to NO ACTION) do not throw.","commonSituations":"TPH/table-splitting where base and derived relationships over the same FK configure different delete behaviors. Inheriting a Cascade FK and overriding to Restrict on one type while reusing the name.","solutions":["Make the OnDelete values consistent across the colliding FKs (same ReferentialAction).","Give the FKs distinct HasConstraintName values when delete behavior must differ.","Decide on a single delete policy for the shared constraint and apply it to both.","Verify ReferentialAction mapping if using NoAction vs Restrict intentionally."],"exampleFix":"// before\nmodelBuilder.Entity<Invoice>().HasOne(i => i.Customer)\n    .WithMany().HasForeignKey(i => i.CustomerId)\n    .OnDelete(DeleteBehavior.Cascade).HasConstraintName(\"FK_Inv_Cust\");\nmodelBuilder.Entity<Invoice>().HasOne(i => i.BillingCustomer)\n    .WithMany().HasForeignKey(i => i.CustomerId)\n    .OnDelete(DeleteBehavior.Restrict).HasConstraintName(\"FK_Inv_Cust\");\n\n// after\nmodelBuilder.Entity<Invoice>().HasOne(i => i.BillingCustomer)\n    .WithMany().HasForeignKey(i => i.CustomerId)\n    .OnDelete(DeleteBehavior.Restrict).HasConstraintName(\"FK_Inv_Cust_Billing\");","handlingStrategy":"validation","validationCode":"// Verify FKs sharing a name resolve to the same referential action\nforeach (var g in allFks.GroupBy(fk => fk.GetConstraintName()))\n{\n    var actions = g.Select(fk => RelationalModel.ToReferentialAction(fk.DeleteBehavior)).Distinct();\n    if (actions.Count() > 1)\n        throw new InvalidOperationException($\"FK {g.Key} has mismatched delete behavior.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize OnDelete for FKs that share a constraint name.","When overriding OnDelete on one type in a shared table, also rename the constraint.","Remember Restrict and NoAction may map to the same action and not collide."],"tags":["efcore","foreign-key","delete-behavior","model-validation","duplicate"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}