hibernate/hibernate-orm · error · AnnotationException

Mapped superclass '{}' may not specify a '@Table'

Error message

Mapped superclass '{}' may not specify a '@Table'

What it means

A '@MappedSuperclass' declares a direct '@Table' annotation. A mapped superclass has no table of its own — its mappings are folded into each subclass's table — so an explicit @Table is meaningless and rejected at bootstrap. Table settings belong to the concrete @Entity at the root of each subclass mapping.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java:291

	private static void handleImport(ClassDetails annotatedClass, MetadataBuildingContext context) {
		if ( annotatedClass.hasDirectAnnotationUsage( Imported.class ) ) {
			final String qualifiedName = annotatedClass.getName();
			final String name = unqualify( qualifiedName );
			final String rename = annotatedClass.getDirectAnnotationUsage( Imported.class ).rename();
			context.getMetadataCollector().addImport( rename.isBlank() ? name : rename, qualifiedName );
		}
	}

	private static void detectMappedSuperclassProblems(ClassDetails annotatedClass) {
		if ( isMappedSuperclass( annotatedClass ) ) {
			// @Entity and @MappedSuperclass on the same class leads to NPE down the road
			if ( isEntity( annotatedClass ) ) {
				throw new AnnotationException( "Type '" + annotatedClass.getName()
						+ "' is annotated both '@Entity' and '@MappedSuperclass'" );
			}
			if ( annotatedClass.hasDirectAnnotationUsage( Table.class ) ) {
				throw new AnnotationException( "Mapped superclass '" + annotatedClass.getName()
						+ "' may not specify a '@Table'" );
			}
			if ( annotatedClass.hasDirectAnnotationUsage( Inheritance.class ) ) {
				throw new AnnotationException( "Mapped superclass '" + annotatedClass.getName()
						+ "' may not specify an '@Inheritance' mapping strategy" );
			}
		}
	}

	private static void bindTypeDescriptorRegistrations(
			AnnotationTarget annotatedElement,
			MetadataBuildingContext context) {
		final var managedBeanRegistry = context.getBootstrapContext().getManagedBeanRegistry();
		final var sourceModelContext = modelsContext( context );

		annotatedElement.forEachAnnotationUsage(
				JavaTypeRegistration.class,
				sourceModelContext,

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove '@Table' from the mapped superclass.
  2. Declare '@Table(name = ...)' on each concrete @Entity subclass instead.
  3. If the base really needs its own table, it must be an '@Entity' with an inheritance strategy, not a '@MappedSuperclass'.

Example fix

// before
@MappedSuperclass
@Table(name = "person_base") // -> error
public abstract class BaseEntity { @Id Long id; }

// after
@MappedSuperclass
public abstract class BaseEntity { @Id Long id; }

@Entity
@Table(name = "person")
class Person extends BaseEntity { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Guard: mapped superclasses must not declare @Table
if (cls.isAnnotationPresent(MappedSuperclass.class)
        && cls.isAnnotationPresent(Table.class)) {
    throw new IllegalStateException(
        cls.getName() + ": @MappedSuperclass may not declare @Table");
}

Try / catch

try {
    Metadata md = sources.buildMetadata();
} catch (AnnotationException e) {
    // 'may not specify a @Table' -> move the @Table to each concrete @Entity
    throw newConfigurationException("Illegal @Table on superclass", e);
}

Prevention

When it happens

Trigger: '@MappedSuperclass @Table(name = "base")' on an abstract class; converting an entity to a superclass without deleting its @Table; generated code emitting a table on every persistent-looking class.

Common situations: Refactoring a concrete entity into a shared base and leaving '@Table' behind; tools/templates that annotate all persistent classes with @Table; misunderstanding that @MappedSuperclass is not a table-backed type.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/15f71198c4c278ab. Report an issue: GitHub.