This implementation of == doesn't "do everything right" because what you are trying to express violates transitivity: two distinct instances of B named b1 and b2 can compare equal to a but compare not equal to each other.
Is there "the right way" here? Or, as with floating point, we obey one rule (IEEE semantics) to break another (a == a).
Say, I want to correct the above code and make subclasses always not equal to base classes. transitivity rule saved, hurrah! But then Liskov substitution principle is broken as I won't be able replacing an object of a class with an object of a subclass without breaking the app (the chosen object previously compared equal to its peers and subclass won't).