Многие вещи, которые мы привыкли причислять к ООП, такие как классы и наследование, это лишь средства моделирования предметной области средствами языка программирования, не более. Теперь по порядку.
Инкапсуляция.
В программе, состоящей из объектов обменивающихся сообщениями, этот принцип выполняется автоматически. Единственное, что может один объект сделать с другим - послать ему сообщение. Другой объект, отреагировав на это сообщение, может изменить свое состояние. Непосредственно изменять состояние друг друга, в нашей гипотетической true OOP системе, объекты не могут. Следовательно, инкапсуляция, лишь средство, с помощью которого принципы ООП реализуются в том или ином языке программирования.
Наследование.
Всего лишь позволяет моделировать отношения между сущностями, не между самими объектами.
Полиморфизм.
Обычно его понимают как subtype полиморфизм - использование объекта производного класса, вместо объекта базового класса. Для нашей true OOP системы это не актуально, так как любому объекту, можно послать любое сообщение. Это актуально для тех языков программирования, в которых передача сообщения объекту реализована как вызов виртуального метода этого объекта.
В качестве примера true OOP системы программирования, можно привести совсем не ООП(по крайней мере в головах mainstream программистов) язык программирования - Erlang. Его процессы - классические объекты, конечно у процесса нет класса, свойств, методов, процессы не наследуются, и так далее. Но, erlang программа - это множество обменивающихся сообщениями процессов/объектов. Получив сообщение, процесс может изменить свое состояние - сделать что-нибудь. Поэтому, erlang - не менее объектно ориентированный, чем Java или Python :)
P.S.
Этим постом я не пытаюсь сказать, что использовать mainstream языки программирования - плохо и что всем нужно срочно переходить на Erlang. Просто мысли вслух :)