The deeper problem is that many domains cannot be modelled as hierarchical taxonomies, but only as ambiguous categories. This is a theory expounded by, amongst others, George Lakoff in his book "Women, Fire and Dangerous Things"[1] and elsewhere. Such cognitive categories are fuzzily defined, often overlap, and represent a collection of traits and properties that members of a category share some or all of. But different members can belong to the category to a greater or less extent, or be better or worse examples of it. E.g. both ostriches and sparrows are birds, but sparrows are usually considered a better example of the category birds.

Like the process of developing scientific taxonomies, efforts to model these kind of domains using OO techniques frequently run into edge cases that defy concrete classification. E.g. can all birds fly? Clearly, flight is an extremely important trait of the class "bird", but we also recognise flightless birds as birds, which means objects can lack an important trait of a category, but still belong to it, albeit as a worse example.

This is not just a theoretical problem. Imagine trying to invent a set of classes to model computing devices for an IT asset management system. What exactly constitutes a smartphone, vs. a tablet, vs. a laptop, etc.? It's easy to imagine the attributes and behaviors you might attach to these classes, but properly mapping every real world device onto them is extremely difficult. You are always going to get edge-case devices that straddle multiple classifications, or exclude some behavior that is assumed to be critical to devices of its type.

The result is that systems trying to model such domains end up with a variety of problems: Some impose a rigid, but essentially arbitrary, taxonomy, with the result that users struggle to use it properly. Edge-cases require special, out-of-band handling, e.g. users understanding that the system cannot properly represent items of a particular type, and that you have to accept a misclassification, or misuse the system slightly in order to make it work.

Some systems flatten and generalise the taxonomy into a single superclass, perhaps called "Device" in our example, that holds all the attributes and behaviors of all the former subclasses. This requires users to then interrogate objects of this generic type and essentially determine their "actual" type on an ad-hoc basis, with the result that they may be treated differently, or incorrectly, by different processes, depending on the heuristics that were applied in that case.

And finally many systems just abandon the idea of internally representing the taxonomy in concrete terms at all. As edge-cases proliferate, and that idea that "every X is just a specialised case of Y", is taken to its conclusion, the concrete taxonomy dissolves and is replaced with a general taxonomical abstraction. A new, more flexible object system is implemented on top of the native object system, such that users of the system can define their own classes, at runtime. These systems will support tagging and multiple membership, and other devices for representing complex taxonomies. This solves the problem of representation, but only by abrogating responsibility for defining it entirely to users of the system. These users are then faced with the task of developing the taxonomy from scratch in userland. In an organisation where different departments need to agree on a common taxonomy, this process is often centralised, and a single simplified set of classes is presented to sub-users. But then edge-cases to this taxonomy start to emerge, and the process repeats itself. This is how layers of abstraction proliferate.

[1] https://en.wikipedia.org/wiki/Women,_Fire,_and_Dangerous_Thi...