dotnet/efcore · error · InvalidOperationException

The foreign keys {foreignKeyProperties1} on '{entityType1}'

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

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.

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 dbf9771522)

Solutions

  1. Make the OnDelete values consistent across the colliding FKs (same ReferentialAction).
  2. Give the FKs distinct HasConstraintName values when delete behavior must differ.
  3. Decide on a single delete policy for the shared constraint and apply it to both.
  4. Verify ReferentialAction mapping if using NoAction vs Restrict intentionally.

Example fix

// before
modelBuilder.Entity<Invoice>().HasOne(i => i.Customer)
    .WithMany().HasForeignKey(i => i.CustomerId)
    .OnDelete(DeleteBehavior.Cascade).HasConstraintName("FK_Inv_Cust");
modelBuilder.Entity<Invoice>().HasOne(i => i.BillingCustomer)
    .WithMany().HasForeignKey(i => i.CustomerId)
    .OnDelete(DeleteBehavior.Restrict).HasConstraintName("FK_Inv_Cust");

// after
modelBuilder.Entity<Invoice>().HasOne(i => i.BillingCustomer)
    .WithMany().HasForeignKey(i => i.CustomerId)
    .OnDelete(DeleteBehavior.Restrict).HasConstraintName("FK_Inv_Cust_Billing");
Defensive patterns

Strategy: validation

Validate before calling

// Verify FKs sharing a name resolve to the same referential action
foreach (var g in allFks.GroupBy(fk => fk.GetConstraintName()))
{
    var actions = g.Select(fk => RelationalModel.ToReferentialAction(fk.DeleteBehavior)).Distinct();
    if (actions.Count() > 1)
        throw new InvalidOperationException($"FK {g.Key} has mismatched delete behavior.");
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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