Because p is not a D*. It is a B*, which happens to be pointing to an instance of D. Nonetheless, the type of the pointer has not changed. In other words, it's catching B* because that's what you're throwing. If you want it to catch D*, then you should throw D*. e.g.: throw static_cast(p); It's worth noting that you cannot use dynamic_cast here, because B is not considered a polymorphic type. i.e. It has no virtual functions.