dotnet/efcore · error · InvalidOperationException

The entity type ' ' is mapped to the stored procedure ' '…

Error message

The entity type '{entityType}' is mapped to the stored procedure '{sproc}', however the properties {properties} are not mapped to any parameter or result column.

What it means

Thrown when, after sproc parameter processing, the `properties` set (entity properties that EF expects to send to the sproc) still has entries that are neither mappable as current-value parameters nor original-value parameters. Each remaining property must have been consumed by a HasParameter/HasOriginalValueParameter call; otherwise the model is incomplete and SaveChanges would silently skip writing data.

Solutions

  1. Add .HasParameter(p => p.TheProperty) (or HasOriginalValueParameter for concurrency tokens) to the relevant sproc mapping for every property listed in the error.
  2. If the property should not be persisted by this sproc (e.g. computed-only, never written), configure it so: .ValueGeneratedOnAddOrUpdate() and AfterSaveBehavior.Ignore / BeforeSaveBehavior.Ignore as appropriate so the validator removes it from the expected set.
  3. Verify IsRequired/IsRequiredWhenSaved semantics — a property declared on the entity but unassigned by the user may still be required by the sproc mapping.

Example fix

// before
entityType.UpdateUsingStoredProcedure("UpdateOrder",
    sp =>
    {
        sp.HasParameter(o => o.OrderId);
        // forgot Status -> listed as unmapped
    });

// after
entityType.UpdateUsingStoredProcedure("UpdateOrder",
    sp =>
    {
        sp.HasParameter(o => o.OrderId);
        sp.HasParameter(o => o.Status);
    });
Defensive patterns

Strategy: validation

Validate before calling

// After building the model, log any property EF considers unmapped for the sproc.
foreach (var et in model.GetEntityTypes())
{
    foreach (var sproc in new[] { et.GetInsertStoredProcedure(), et.GetUpdateStoredProcedure(), et.GetDeleteStoredProcedure() })
    {
        if (sproc == null) continue;
        var mapped = sproc.Parameters.Select(p => p.PropertyName).Where(n => n != null).ToHashSet();
        foreach (var prop in et.GetProperties())
        {
            if (!mapped.Contains(prop.Name)
                && (et.GetTableName() != null || prop.IsPrimaryKey() || prop.IsConcurrencyToken))
            {
                // Heuristic: only flag properties the validator would expect.
                Console.WriteLine($"{et.Name}.{prop.Name} not present on {sproc.Name}.");
            }
        }
    }
}

Prevention

When it happens

Trigger: An entity has properties that the validator cannot reconcile with any sproc parameter, result column, or original-value slot. Specifically: on Update sproc, a property that is a non-key, non-concurrency-token, non-OnUpdate-generated, non-Save-after-save-behavior property but is still expected to be persisted; on Insert sproc, a non-OnAdd, non-Save-before-save-behavior property; or any property the developer expects the sproc to handle but did not map.

Common situations: Adding a new property to the entity and forgetting to add the sproc parameter; mapping only some columns of a table to the sproc; mixing TPH inheritance where derived properties are not surfaced in the sproc.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:901

                        {
                            properties.Remove(property.Name);
                        }

                        break;
                }
            }

            foreach (var property in properties.Keys.ToList())
            {
                if (!originalValueProperties.ContainsKey(property))
                {
                    properties.Remove(property);
                }
            }

            if (properties.Count > 0)
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedurePropertiesNotMapped(
                        entityType.DisplayName(),
                        storeObjectIdentifier.DisplayName(),
                        properties.Values.Format()));
            }
        }

        if (sproc.IsRowsAffectedReturned
            || sproc.FindRowsAffectedParameter() != null
            || sproc.FindRowsAffectedResultColumn() != null)
        {
            if (storeObjectIdentifier.StoreObjectType == StoreObjectType.InsertStoredProcedure)
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureRowsAffectedForInsert(
                        storeObjectIdentifier.DisplayName()));
            }

View on GitHub (pinned to 3a2006ef56)