{"record":{"id":"66a086a5a5d7cff7","repo":"dotnet/efcore","slug":"entitytype-is-mapped-to-the-stored-procedure","errorCode":null,"errorMessage":"'{entityType}' is mapped to the stored procedure '{sproc}' while '{otherEntityType}' is mapped to the stored procedure '{otherSproc}'. Map all the entity types in the hierarchy to the same stored procedure, or remove the discriminator and map them all to different stored procedures. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information.","messagePattern":"'(.+?)' is mapped to the stored procedure '(.+?)' while '(.+?)' is mapped to the stored procedure '(.+?)'\\. Map all the entity types in the hierarchy to the same stored procedure, or remove the discriminator and map them all to different stored procedures\\. See https://go\\.microsoft\\.com/fwlink/\\?linkid=2130430 for more information\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":2347,"sourceCode":"                case StoreObjectType.Table:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphTableMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.View:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphViewMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.Function:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphDbFunctionMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.InsertStoredProcedure:\n                case StoreObjectType.DeleteStoredProcedure:\n                case StoreObjectType.UpdateStoredProcedure:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphStoredProcedureMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n            }\n        }\n    }\n\n    /// <inheritdoc />\n    protected override bool IsRedundant(IForeignKey foreignKey)\n        => base.IsRedundant(foreignKey)\n            && !foreignKey.DeclaringEntityType.GetMappingFragments().Any();\n\n    /// <summary>\n    ///     Validates the mapping fragments for an entity type.\n    /// </summary>\n    /// <param name=\"entityType\">The entity type to validate.</param>\n    /// <param name=\"logger\">The logger to use.</param>\n    protected virtual void ValidateMappingFragment(","sourceCodeStart":2329,"sourceCodeEnd":2365,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2329-L2365","documentation":"Thrown inside ValidateTphMapping when a derived type resolves to a different Insert/Delete/Update stored procedure StoreObjectIdentifier than the root. TPH requires the whole hierarchy to use the same stored procedure (defined on the root), so a derived type mapped to a different sproc is rejected.","triggerScenarios":"A TPH hierarchy where the root declares a *UsingStoredProcedure and a derived type resolves to a different stored procedure (different name/store object) rather than reusing the root's.","commonSituations":"Per-type stored procedure config accidentally applied to a derived type in TPH; partial TPT migration; copy-paste of sproc config across the hierarchy.","solutions":["Configure the stored procedure only on the root and include all derived-type parameters there.","Switch the hierarchy to TPT/TPC if separate stored procedures per type are genuinely needed."],"exampleFix":"// before (TPH, different sproc on derived)\nmodelBuilder.Entity<Person>().UpdateUsingStoredProcedure(\"sp_UpdatePerson\");\nmodelBuilder.Entity<Customer>().UpdateUsingStoredProcedure(\"sp_UpdateCustomer\"); // throws 435\n\n// after (single sproc on root)\nmodelBuilder.Entity<Person>().UpdateUsingStoredProcedure(\"sp_UpdatePerson\")\n    .HasParameter(\"ShippingAddress\", p => ((Customer)p).ShippingAddress);","handlingStrategy":"validation","validationCode":"foreach (var root in modelBuilder.Model.GetEntityTypes().Where(t => t.BaseType == null))\n{\n    if (root.FindDiscriminatorProperty() == null) continue;\n    foreach (var sot in new[] { StoreObjectType.InsertStoredProcedure, StoreObjectType.DeleteStoredProcedure, StoreObjectType.UpdateStoredProcedure })\n    {\n        var rootSo = StoreObjectIdentifier.Create(root, sot);\n        if (rootSo == null) continue;\n        foreach (var et in root.GetDerivedTypes())\n        {\n            var so = StoreObjectIdentifier.Create(et, sot);\n            if (so != null && so.Value != rootSo.Value)\n                throw new InvalidOperationException($\"{et.DisplayName()} {sot} {so.Value.DisplayName()} differs from root {rootSo.Value.DisplayName()} (TPH).\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In TPH, declare stored procedures on the root only.","Switch to TPT/TPC if separate stored procedures per type are needed.","Add a model test that verifies sproc consistency across a TPH hierarchy."],"tags":["ef-core","model-validation","mapping","inheritance","tph","stored-procedures"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}