Let me provide a different, yet typical, answer: it depends.
A lot of people (me included) have troubles with inheritance hierarchies such as the ones @greyfade mentioned in the other answer. The clean code mantra "prefer composition over inheritance" stems from exactly that.
However, by understanding the problems that are at the root of inheritance hierarchies you can still get the best of both worlds. Keep in mind though, that this is heavily dependent on your language and your self-discipline.
What you have described is something that simply was not possible in a language like Java (prior to Java 8, which got default interfaces now), but readily accepted in C++ before and more modern languages like C# or Scala. In order to save themselves the tedious discussions originating from the above-mentioned troubles though, they chose to call these "mixins" or "traits" (as opposed to "multiple" "inheritance" - two words that are readily attackable by everyone with a basic CS degree). Yet in essence, your description sounds just like you're doing that.
What's important in a trait-based approach, just as well as in one based on composition (instead of inheritance), is to focus on two primary advantages:
You want to be able to reuse one of these "things" without having to bother about the others
and want to be able to change or replace one of these, again without having to care too much about the others.
Clearly, when you have a full hierarchy of things in a large tree, it is near to impossible to get these two advantages for an implementation class that sits somewhere in the middle of that tree. Nevertheless, when you work with traits/mixins, or essentially do the same thing via self-discipline in C++ in that you do inherit multiple times, but not form a hierarchy that has a depth greater than a single inheritance step, then you have technically used inheritance, yet you get to keep all those advantages.
You can reuse each of the individual parts independently, or even exchange them with reasonably little work. Yet this system does not save you from potentially creating intangible class hierarchies again (but then again, neither does a hammer save you from hitting your head with it).
With regards to entity systems, I am personally not convinced of their superiority over traits. Both are way better than creating a big inheritance hierarchy though. Also I'm not in the gaming industry, so other effects (like the mentioned fast memory accesses) may also be important enough to your use case to justify choosing one way over the other. As usual, there is no silver bullet (unless you create one in your game) and everything has its pros and cons. Just make sure you understand the downsides of whichever way you choose.
In response to the add-on comment question(s):
It's not like the different approaches differ by being suitable or not for a simple game. I don't believe you have scalability issues with either. Traits/Mixins are quite successfully being used in rather large systems and scale well, especially because they are so nicely composable. No idea how scalability came up, but it's not really an issue for either approach here as far as I can tell.
Addressing your comment, as far as I understand it data-driven doesn't mean you have a standard composition via an attribute in your class. So your
Entity class doesn't directly refer to a
Position class, because that would again result in higher coupling than intended. To add a "component" to an entity you would still have to go into that class. As far as I can tell, and please be aware I'm no expert on that, the idea is to decouple your Entity from having to know the concrete "component" thing at all, but instead rely on some intermediate representation. A very simplified example may be that your entity is a key-value store and your Health component results in a
"health" -> 10 entry into that store. This way, the outside world can add components to the entity, without the entity itself having to know anything about these components.
I'm not sure if I understand the gaming gurus idea correctly though (corrections from someone who knows better are always welcome), but I am under the impression that with this approach you sacrifice a lot of compile-time safety and reasoning abilities as the trade-off to gain very low coupling (hence the good scripting options with Lua and such) and potentially faster implementation possibilities (by memory alignments of this component data to optimize memory/cache accesses). Assuming that is correct, I could still not claim one way to be the right one. We all have our preferences and outside requirements that should be satisfied as best as possible.