{"record":{"id":"199a679885e330cf","repo":"dotnet/efcore","slug":"the-indexes-index1-on-entitytype1-and-index","errorCode":null,"errorMessage":"The indexes {index1} on '{entityType1}' and {index2} on '{entityType2}' are both mapped to '{indexName}', but are declared on different tables ('{table1}' and '{table2}').","messagePattern":"The indexes (.+?) on '(.+?)' and (.+?) on '(.+?)' are both mapped to '(.+?)', but are declared on different tables \\('(.+?)' and '(.+?)'\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs","lineNumber":55,"sourceCode":"    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public static bool AreCompatible(\n        this IReadOnlyIndex index,\n        IReadOnlyIndex duplicateIndex,\n        in StoreObjectIdentifier storeObject,\n        bool shouldThrow)\n    {\n        var columnNames = index.GetColumnNames(storeObject);\n        var duplicateColumnNames = duplicateIndex.GetColumnNames(storeObject);\n        if (columnNames == null\n            || duplicateColumnNames == null)\n        {\n            return shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateIndexTableMismatch(\n                        index.DisplayName(),\n                        index.DeclaringEntityType.DisplayName(),\n                        duplicateIndex.DisplayName(),\n                        duplicateIndex.DeclaringEntityType.DisplayName(),\n                        index.GetDatabaseName(storeObject),\n                        index.DeclaringEntityType.GetSchemaQualifiedTableName(),\n                        duplicateIndex.DeclaringEntityType.GetSchemaQualifiedTableName()))\n                : false;\n        }\n\n        if (!columnNames.SequenceEqual(duplicateColumnNames))\n        {\n            return shouldThrow\n                ? throw new InvalidOperationException(\n                    RelationalStrings.DuplicateIndexColumnMismatch(\n                        index.DisplayName(),\n                        index.DeclaringEntityType.DisplayName(),","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs#L37-L73","documentation":"Thrown by RelationalIndexExtensions.AreCompatible during model validation when two indexes resolve to the same database name on a store object, but GetColumnNames(storeObject) returns null for at least one of them — i.e. the indexes' properties cannot be mapped to columns on that shared table. The message frames it as 'declared on different tables' because a null column-name set means the index does not actually target the store object the duplicate lives on. EF refuses to let one index name describe two indexes that do not share a concrete column set on one table.","triggerScenarios":"AreCompatible(index, duplicateIndex, storeObject, shouldThrow: true) at RelationalIndexExtensions.cs:51-64, invoked from model validation when two IReadOnlyIndex instances share GetDatabaseName(storeObject) but one returns null from GetColumnNames. Happens when HasIndex(...).HasDatabaseName(\"X\") is applied on entity types that map to different physical tables, or when a JSON-mapped/scalar property inside the index has no container column name (GetColumnNames returns null at line 158/173/194).","commonSituations":"Two entities each call HasDatabaseName with the same literal index name without realizing EF will treat them as one shared index; entity splitting or TPT inheritance where a derived-type index name collides with a base-type index on a different table; copying an index configuration across entity types that are not table-sharing.","solutions":["Rename one of the indexes so each table has a distinct database name (drop the explicit HasDatabaseName, or give the second a unique name).","If the two entity types genuinely share one table (entity splitting / table sharing), ensure both actually map to that same table and that all index properties resolve to columns on it.","Remove the conflicting HasIndex/HasDatabaseName on one side and let EF generate a default unique name.","Inspect index.GetDatabaseName(storeObject) and index.GetColumnNames(storeObject) for both indexes in a validation hook to confirm they collide and why the column set is null."],"exampleFix":"// before\nmodelBuilder.Entity<Customer>().HasIndex(c => c.Code).HasDatabaseName(\"IX_Code\");\nmodelBuilder.Entity<Vendor>().HasIndex(v => v.Code).HasDatabaseName(\"IX_Code\"); // different tables -> throws\n\n// after\nmodelBuilder.Entity<Customer>().HasIndex(c => c.Code).HasDatabaseName(\"IX_Code\");\nmodelBuilder.Entity<Vendor>().HasIndex(v => v.Code).HasDatabaseName(\"IX_Vendor_Code\");","handlingStrategy":"validation","validationCode":"// Before finalizing the model, ensure each shared index name resolves columns on one table\nforeach (var et in model.GetEntityTypes())\n{\n    foreach (var idx in et.GetDeclaredIndexes())\n    {\n        foreach (var table in et.GetTableMappings())\n        {\n            var storeObj = table.Table is ITable t\n                ? StoreObjectIdentifier.Table(t.Name, t.Schema)\n                : (StoreObjectIdentifier?)null;\n            if (storeObj is { } so\n                && idx.GetColumnNames(so) is null\n                && !string.IsNullOrEmpty(idx.GetDatabaseName(so)))\n            {\n                throw new InvalidOperationException($\"Index {idx.GetDatabaseName(so)} on {et.Name} does not resolve to columns on {so.DisplayName()}\");\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid hardcoding HasDatabaseName across entity types that do not share a table.","When table-splitting, centralize index declarations on the principal entity type.","Add an integration test that builds the model and runs ValidateModel to surface duplicate-index conflicts in CI."],"tags":["relational","model-validation","index","table-mapping"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}