dotnet/efcore · error · InvalidOperationException

The indexes {index1} on '{entityType1}' and {index2} on '{en

Error message

The indexes {index1} on '{entityType1}' and {index2} on '{entityType2}' are both mapped to '{table}.{indexName}', but with different columns ({columnNames1} and {columnNames2}).

What it means

Thrown by RelationalIndexExtensions.AreCompatible when two indexes share the same database name AND table, but resolve to different column lists (columnNames vs duplicateColumnNames differ per SequenceEqual). EF requires indexes that share one name on one table to describe the same column ordering, because they are one physical index in the database.

Source

Thrown at src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs:70

            || duplicateColumnNames == null)
        {
            return shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateIndexTableMismatch(
                        index.DisplayName(),
                        index.DeclaringEntityType.DisplayName(),
                        duplicateIndex.DisplayName(),
                        duplicateIndex.DeclaringEntityType.DisplayName(),
                        index.GetDatabaseName(storeObject),
                        index.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        duplicateIndex.DeclaringEntityType.GetSchemaQualifiedTableName()))
                : false;
        }

        if (!columnNames.SequenceEqual(duplicateColumnNames))
        {
            return shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateIndexColumnMismatch(
                        index.DisplayName(),
                        index.DeclaringEntityType.DisplayName(),
                        duplicateIndex.DisplayName(),
                        duplicateIndex.DeclaringEntityType.DisplayName(),
                        index.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        index.GetDatabaseName(storeObject),
                        FormatColumnNames(columnNames),
                        FormatColumnNames(duplicateColumnNames)))
                : false;
        }

        return index.IsUnique != duplicateIndex.IsUnique
            ? shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateIndexUniquenessMismatch(
                        index.DisplayName(),
                        index.DeclaringEntityType.DisplayName(),

View on GitHub (pinned to dbf9771522)

Solutions

  1. Make the two indexes target the same properties (and the same column names via HasColumnName) so the resolved column lists match.
  2. Give each index a distinct database name with HasDatabaseName.
  3. Remove the redundant index from one entity type so only one definition exists for that name.
  4. Verify with index.GetColumnNames(storeObject) on both sides that the column ordering now matches exactly.

Example fix

// before
modelBuilder.Entity<Order>().HasIndex(o => o.CustomerId).HasDatabaseName("IX_Cust");
modelBuilder.Entity<Refund>().HasIndex(r => r.OriginId).HasDatabaseName("IX_Cust"); // same table, different columns -> throws

// after
modelBuilder.Entity<Refund>().HasIndex(r => r.CustomerId).HasDatabaseName("IX_Cust");
Defensive patterns

Strategy: validation

Validate before calling

// Confirm two indexes sharing a database name resolve to identical column lists
static bool ColumnsMatch(IReadOnlyIndex a, IReadOnlyIndex b, StoreObjectIdentifier so)
    => a.GetDatabaseName(so) == b.GetDatabaseName(so)
        && a.GetColumnNames(so) is { } ca
        && b.GetColumnNames(so) is { } cb
        && ca.SequenceEqual(cb);

Prevention

When it happens

Trigger: Line 67-80 of RelationalIndexExtensions.cs: the null check passes (both indexes resolve to columns) but columnNames.SequenceEqual(duplicateColumnNames) is false. Produced when HasIndex with different property lists on two table-sharing entity types carries the same HasDatabaseName.

Common situations: Table-splitting two entities onto one table and giving both an index the same name but over different properties; renaming a property's column on one entity without updating the index; TPH/TPT where a base and derived index collide on name but cover different columns.

Related errors


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