dotnet/efcore · error · InvalidOperationException

The entity type '{entityType}' is mapped to a SQL query, but

Error message

The entity type '{entityType}' is mapped to a SQL query, but is derived from '{baseEntityType}'. Derived entity types cannot be mapped to a different SQL query than the base entity type.

What it means

ValidateSqlQuery (RelationalModelValidator.cs:332-339) throws when an entity type that has a base type (is derived) is mapped to a SQL query (ToSqlQuery/defining query) whose definition differs from its base type's, or when the derived type has no discriminator. EF requires the whole hierarchy to read from the same SQL query, so a derived type mapping to its own SQL query is rejected.

Source

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

    ///     Validates the SQL query mapping for an entity type.
    /// </summary>
    /// <param name="entityType">The entity type to validate.</param>
    /// <param name="logger">The logger to use.</param>
    protected virtual void ValidateSqlQuery(
        IEntityType entityType,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        var sqlQuery = entityType.GetSqlQuery();
        if (sqlQuery == null)
        {
            return;
        }

        if (entityType.BaseType != null
            && (entityType.FindDiscriminatorProperty() == null
                || sqlQuery != entityType.BaseType.GetSqlQuery()))
        {
            throw new InvalidOperationException(
                RelationalStrings.InvalidMappedSqlQueryDerivedType(
                    entityType.DisplayName(), entityType.BaseType.DisplayName()));
        }
    }

    /// <summary>
    ///     Validates a single sequence.
    /// </summary>
    /// <param name="sequence">The sequence to validate.</param>
    /// <param name="logger">The logger to use.</param>
    protected virtual void ValidateSequence(
        ISequence sequence,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
    }

    /// <summary>
    ///     Validates a single database function.

View on GitHub (pinned to dbf9771522)

Solutions

  1. Define the SQL query only on the base/root entity type and let derived types share it (with a discriminator for TPH).
  2. Ensure the derived type either has no SQL query (inherits the base's) or the same SQL query string as the base.
  3. If each type needs distinct SQL, model them as separate entity types (no inheritance) or separate keyless entities.

Example fix

// before - derived type mapped to its own SQL
modelBuilder.Entity<Person>().ToSqlQuery("SELECT * FROM People");
modelBuilder.Entity<Employee>().ToSqlQuery("SELECT * FROM Employees"); // throws

// after - share the base SQL, discriminate by column
modelBuilder.Entity<Person>().ToSqlQuery("SELECT * FROM People");
modelBuilder.Entity<Person>().HasDiscriminator(p => p.Type);
// do not call ToSqlQuery on Employee; it inherits the base query
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in context.Model.GetEntityTypes())
{
    if (et.GetSqlQuery() != null && et.BaseType != null)
    {
        var baseQuery = et.BaseType.GetSqlQuery();
        if (et.FindDiscriminatorProperty() == null || et.GetSqlQuery() != baseQuery)
        {
            // will throw - map SQL query only on the base and share it.
        }
    }
}

Prevention

When it happens

Trigger: Calling ToSqlQuery(...) (or setting GetSqlQuery) on a derived entity type with a different SQL than the base, or removing the discriminator while mapping a derived type to SQL. Thrown at model validation.

Common situations: Inheritance hierarchies where each derived type tries to supply its own raw SQL; refactoring a keyless SQL-query mapping into a hierarchy; mixing TPT/TPC with SQL-query mappings.

Related errors


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