dotnet/efcore · error · InvalidOperationException

'{entityType}' is mapped to the view '{view}' while '{otherE

Error message

'{entityType}' is mapped to the view '{view}' while '{otherEntityType}' is mapped to the view '{otherView}'. Map all the entity types in the hierarchy to the same view, or remove the discriminator and map them all to different views. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information.

What it means

ValidateTphMapping for StoreObjectType.View: identical rule to TphTableMismatch but for views. A TPH hierarchy must map all types to the same view; a derived type resolving to a different view StoreObjectIdentifier than the root is rejected.

Source

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

                    {
                        throw new InvalidOperationException(
                            RelationalStrings.StoredProcedureTphDuplicate(
                                entityType.DisplayName(), rootEntityType.DisplayName(), rootId?.DisplayName()));
                    }
                }

                continue;
            }

            switch (storeObjectType)
            {
                case StoreObjectType.Table:
                    throw new InvalidOperationException(
                        RelationalStrings.TphTableMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
                case StoreObjectType.View:
                    throw new InvalidOperationException(
                        RelationalStrings.TphViewMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
                case StoreObjectType.Function:
                    throw new InvalidOperationException(
                        RelationalStrings.TphDbFunctionMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
                case StoreObjectType.InsertStoredProcedure:
                case StoreObjectType.DeleteStoredProcedure:
                case StoreObjectType.UpdateStoredProcedure:
                    throw new InvalidOperationException(
                        RelationalStrings.TphStoredProcedureMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
            }
        }
    }

View on GitHub (pinned to dbf9771522)

Solutions

  1. Drop the per-derived .ToView so all types share the root view.
  2. Remove the discriminator to switch to TPT, then map each type to its own view.
  3. Point the derived type at the SAME view name/schema as the root.

Example fix

// before
modelBuilder.Entity<Base>().HasDiscriminator(b => b.Kind).ToView("v_Base");
modelBuilder.Entity<Derived>().ToView("v_Derived");

// after
modelBuilder.Entity<Base>().HasDiscriminator(b => b.Kind).ToView("v_Base");
// derived omitted, inherits root view
Defensive patterns

Strategy: validation

Validate before calling

bool TphAllTypesSameView(DbContext context)
{
    foreach (var root in context.Model.GetEntityTypes()
        .Where(e => e.BaseType == null && e.FindDiscriminatorProperty() != null && e.GetDerivedTypes().Any()))
    {
        var rootView = StoreObjectIdentifier.Create(root, StoreObjectType.View);
        if (rootView is null) continue;
        foreach (var d in root.GetDerivedTypes())
            if (StoreObjectIdentifier.Create(d, StoreObjectType.View) is { } dv && dv != rootView) return false;
    }
    return true;
}

Try / catch

try { _ = context.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("mapped to the view", StringComparison.Ordinal) && ex.Message.Contains("same view", StringComparison.Ordinal))
{
    throw new InvalidOperationException("A TPH hierarchy must keep all types on one view. Remove the derived .ToView or drop the discriminator for TPT.", ex);
}

Prevention

When it happens

Trigger: Root has a discriminator (TPH) and a ToView, and a derived type was given a different .ToView("OtherView"), so its StoreObjectIdentifier differs from rootId.

Common situations: Read-only TPH model where one derived type was pointed at a different view; scaffolding views then enabling a discriminator.

Related errors


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