When intelligent people are talking about different "kinds of objects", they are used to describe objects in terms of "flavors", "behaviors", "traits", while idiots tend to talk about "classes".
There are abstract, ephemeral creations of a mind, which almost always are in contradiction with so-called real world. Ideas, concepts, even logic, they are usually utopias or disconnected from reality oversimplifications.
Lets be very careful here. Numbers in Math are very good example. A number can be either of this or that "type". And it *sometimes* could be "coerced" into another "class" without "losing precision".
This is the most sacred notion of proponents of strictness and rigidness, so-called "strong typing", "strict languages", fixed routines.
Lets call this a "OR-mind". It is a rather naive notion that "things are either this or that, right or wrong, black or white, integer or rational (yeah, numbers are a special case).
This is the "naive logic" everyone begins with. Later they are trying to use "strict", "rigid categories" of the same kind. This is how wast (but meaningless) class hierarchies were created. And, indeed, in case of numbers they are good. As long as there is nothing but numbers to "model" Java is a great, the most strict language. Packers love it.
In so-called objective reality, however, their "strict" and "rigid" hierarchical classifications are failing. Packers are trying to classify the phenomena of the Nature in terms of "strong is-a", "strict this OR that" and fail.
They are talking about birds as something that "has wings" but there are bats and fish. They say that it "has wings" and "lay eggs" but there are reptiles. (they usually doesn't know that birds *were* reptiles, but that's OK - they have no notion of "were" in the packer's world)
First packers have tried to remove contradiction with so-called "multiple-inheritance". They could say "this IS this AND that", which is also a naive. Ostrich "is-a" Bird but while the method "HasWings()" returns "True", the call to the method "flyThere()" produces a very long stack trace.
Then "generics" and "interfaces" were added much later to these "packer's" languages (to mess everything up even more) so they could create "compound objects" as a "collection of traits".
Less "rigid" people, however, had the notion of so-called "duck-typing" from the very beginning. Smalltalk and modeled after it the Flavors DLS (the mother of CLOS) has exactly this approach. If it can do this-AND-that (follows the protocol) then it could be viewed (considered) as "one-of" this kind. This way of thinking we could describe as the "AND-mind". Less restricted, "light", context-aware.
The notion of "pattern matching" which is based exactly on the notion of "catching" different nuances (particulars, subtleties) of reality is closely related to a such mind-set.
Now about "type safety" meme. Again, if the world consist only of numbers and abstract ideas, then, perhaps, it could make some sense. However, processes are not "linear", classifications are not "three-like" when everything is just this OR that. Reality is much more complex than that.
Such naivety manifests itself when packers are trying to "model" moderately complex systems. They think that "there is a Stream, so we could define a class with methods. While reading a stream we will get Either data OR Nothing" they say. "So as our code covers both "cases", and the compiler checks the types of variables we are safe!". OK, what they got instead is SIGPIPE signal, or EAGAIN error code or "connection reset by peer" state, which are of very different "type".
Well, they say these are not our problems, it must be handled by runtime. We want Either data or Nothing, we don't want any signals, or states, or conditions.
In other words, when learning OO, follow the best minds, those behind Smalltalk or CLOS, which have a "correct" notion of what OOP is and what it is for. It is a way to structure the code for reuse and to avoiding duplication. It is a way to model a "complex" representation of real-world "objects" by composing an distinct, usually unrelated "behaviors" or "traits". It is about communication between these "objects", strong isolation of each particular "instance", and encapsulation of the its "internal state".
All this was implemented using only "conses", "closures" and "message-passing".
There is a beautiful and telling similarity between
defclass "special forms" in Common Lisp. Classes are viewed just as "structured expressions" while expressions themselves are "data to be evaluated". Code is data, so it could be "structured" this or that way.
Thus, logically, OO "adds a second (and third, etc) dimension" to the code, the same way "structures" do for the data. As long as one treats code as data, everything is perfectly natural and "logical".
The most important real-world idea behind OO is, perhaps, that something could exhibit more that one behavior, has more than one trait, the way people do. Food has more than one flavor too.
So, OO programming is not only about the way of packaging a code into methods of classes and enforcing the restriction that "every object must be a memeber of a class" (for most Java or Ruby coders OO ends here), but rather a way to model real-world objects by structuring the data not just as "2D-trees of variables of this OR that type" but as "nD-graphs of expressions AND actors/agents".
The people behind Lisps, Smalltalk, MOP/CLOS were much brighter, broad-minded, better educated and more enthusiastic than most of modern "punks".