Hibernate creating wrong entity subtype in relationship

With Hibernate 5.0.2.Final I was able to make your example work using @ManyToOne(..., targetEntity = A.class). I also replaced public abstract AClass getA(); with an ordinary getter.

@Entity
@Table(name = "B")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1)
public abstract class B<AClass extends A> {
    private Long id;
    private AClass a;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @ManyToOne(fetch = FetchType.EAGER, targetEntity = A.class)
    @JoinColumn(name = "A_ID")
    public AClass getA() {
        return a;
    }

    public void setA(AClass a) {
        this.a = a;
    }
}
@Entity
@DiscriminatorValue("1")
public class B1 extends B<A1> {
    // no need to override getA()
}
@Entity
@DiscriminatorValue("2")
public class B2 extends B<A2> {
    // no need to override getA()
}

I did not find anything about this behavior in the documentation. So I have only my observations:

  • Without targetEntity = A.class Hibernate didn't even query the DISCRIMINATOR column of table A when eagerly fetching rows from A along with B, like it already made a decision about actual type of A.
  • When I added targetEntity = A.class, A.DISCRIMINATOR appeared in the queries, and objects were created with the right sub-classes of class A.

You are using the same join column (A_ID) in both B1 and B2 subclasses.

Use different one in each subclass:

@Entity
@DiscriminatorValue("1")
public class B1 extends B<A1> {
    @Override
    @ManyToOne(fetch = EAGER)
    @JoinColumn(name = "A1_ID")
    public A1 getA() { ... }
}

@Entity
@DiscriminatorValue("2")
public class B2 extends B<A2> {
    @Override
    @ManyToOne(fetch = EAGER)
    @JoinColumn(name = "A2_ID")
    public A2 getA() { ... }
}

Although it may make sense to reuse the column (with different columns one will anyway be null for each record depending on the subclass), it seems that Hibernate uses column names internally to uniquely identify some mapping elements within the same table. That's why it probably ignores the definition of the many-to-one mapping in B1 and uses the one from B2 for it as well (because B2 is defined before B1 in the persistence.xml).