I was wondering if you could take a look at the following program. I would have expected it to fail with a ClassCastException, but it turns out to run OK. Why would I expect it to fail? Well, I'm invoking the method c.self(). Since C puts T = B, this method (inherited from A) should be attempting to cast "this" to B, which is clearly impossible since "this" is an instance of C and is unrelated to the class B (in fact no instance of B was ever created). However, everything works out fine since the caller actually doesn't use the returned object for anything. It turns out that if we replace the main() method by:

C c = new C();
B b = c.self();
System.out.println("Hello.");

We actually get the expected ClassCastException - but not in A as I would have expected but in Main, due to the assignment of c.self() to b which is of type B - even though the culprit class (which generates a warning, as it should) is in A.

Is this correct and could someone point me to the place in JLS that means that it is OK to skip type checks such as this? Thanks.

Generics are erased at compile time. Specifically, T is erased to its upper bound, which is A. The type check you refer to therefore cannot occur inside the self() method, so it occurs where the result of self() is assigned in the caller. If it isn't assigned, no error.