dotnet/efcore · error · InvalidOperationException

The foreign keys on ' ' and on ' ' are both mapped to ' …

Error message

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}').

What it means

Two foreign keys share a constraint name and table but have different DeleteBehavior values (translated to different referential actions such as Cascade vs Restrict). The database constraint can only encode one action.

Solutions

  1. Align both FKs to the same OnDelete behavior.
  2. Give the FKs distinct constraint names via HasConstraintName.
  3. Remove or remap the redundant FK if only one relationship is intended.
  4. If the duplicate is from TPT/splitting, consolidate the relationship definitions so a single DeleteBehavior applies.

Example fix

// before
modelBuilder.Entity<Order>().HasOne(o => o.Customer).WithMany().OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Refund>().HasOne(r => r.Customer).WithMany().OnDelete(DeleteBehavior.NoAction);
// both default to the same constraint name -> mismatch

// after: align behaviors or rename
modelBuilder.Entity<Order>().HasOne(o => o.Customer).WithMany().OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Refund>().HasOne(r => r.Customer).WithMany().OnDelete(DeleteBehavior.Cascade);
Defensive patterns

Strategy: validation

Validate before calling

// Verify DeleteBehavior consistency across colliding FKs.
var fks = modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys());
foreach (var fk in fks)
{
    var name = fk.GetConstraintName();
    foreach (var dup in fks.Where(o => o != fk && o.GetConstraintName() == name))
    {
        if (fk.DeleteBehavior != dup.DeleteBehavior)
            Console.WriteLine($"DeleteBehavior mismatch on '{name}': {fk.DeleteBehavior} vs {dup.DeleteBehavior}.");
    }
}

Prevention

When it happens

Trigger: RelationalForeignKeyExtensions.AreCompatible with shouldThrow:true when RelationalModel.ToReferentialAction(foreignKey.DeleteBehavior) != ToReferentialAction(duplicateForeignKey.DeleteBehavior). Occurs when two relationships share a constraint name but one sets OnDelete(Cascade) and the other OnDelete(NoAction) (or ClientSetNull/Restrict).

Common situations: An owned entity and a regular reference to the same principal both ending up on the same columns; manually setting OnDelete differently on two relationships that default to the same constraint name; migration scaffolding after a DeleteBehavior change that conflicts with a pre-existing constraint.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/86f1220ceb3cd98f. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs:132

        if (foreignKey.IsUnique != duplicateForeignKey.IsUnique)
        {
            return shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateForeignKeyUniquenessMismatch(
                        foreignKey.Properties.Format(),
                        foreignKey.DeclaringEntityType.DisplayName(),
                        duplicateForeignKey.Properties.Format(),
                        duplicateForeignKey.DeclaringEntityType.DisplayName(),
                        foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        foreignKey.GetConstraintName(storeObject, principalTable.Value)))
                : false;
        }

        var referentialAction = RelationalModel.ToReferentialAction(foreignKey.DeleteBehavior);
        var duplicateReferentialAction = RelationalModel.ToReferentialAction(duplicateForeignKey.DeleteBehavior);
        return referentialAction != duplicateReferentialAction
            ? shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateForeignKeyDeleteBehaviorMismatch(
                        foreignKey.Properties.Format(),
                        foreignKey.DeclaringEntityType.DisplayName(),
                        duplicateForeignKey.Properties.Format(),
                        duplicateForeignKey.DeclaringEntityType.DisplayName(),
                        foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        foreignKey.GetConstraintName(storeObject, principalTable.Value),
                        referentialAction,
                        duplicateReferentialAction))
                : false
            : foreignKey.IsExcludedFromMigrations() == duplicateForeignKey.IsExcludedFromMigrations()
            || (shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateForeignKeyExcludedFromMigrationsMismatch(
                        foreignKey.Properties.Format(),
                        foreignKey.DeclaringEntityType.DisplayName(),
                        duplicateForeignKey.Properties.Format(),
                        duplicateForeignKey.DeclaringEntityType.DisplayName(),

View on GitHub (pinned to 3a2006ef56)