Well, it depends how you want to use those classes. If you want them to be serialized so they can be edited in the Unity editor and “assigned” to gameobjects it won’t work the way you have it right now. Unity can serialize custom classes but does not support inheritance for those. Also those classes wouldn’t be serialized on their own but are simply part of the MonoBehaviour that it contains.
If you create and manage all your items in code and at runtime, it’s fine to use the classes as you have them right now. Just add an “ItemHolder” class to your gameobject and assign whatever item you want to the Item variable. Since they are all derived from your Item base class this works just fine. Of course accessing specialized fields can’t be done without knowing the actual type.
However if you want to have them serialized you should either derive your base class from MonoBheaviour or ScriptableObject.
When you use MonoBehaviour as base class for your Item class you would simply attach an concrete implementation to your GameObject.
if you want to “define” different “item types” using the same class (small med kit, medium med kit, large med kit, …) it’s better to use a ScriptableObject and create assets for each item type.
The point of inheritance is to abstract a concept. So if you don’t going to implement any virtual methods which you might override in your sub classes it’s questionable why you use inheritance in the first place. Again, how you want to use your classes? For example the Item class could define a virtual (or abstract) “Use” method which will be overridden by the different sub classes. The item system doesn’t need to “know” what kind of item that is. You just call “Use” on the item and the item itself knows what it has to do.
Unity actually uses a component system which usually does not rely on deep inheritance chains but on a flat hierarchy. A component is made for a certain purpose. The final object might have several components attached. For example you could have a simple “Item” script. It just defines basic item properties that every item needs. In addition you could add a “Pickable” component. The pickup system can only pickup things with that script attached. It wouldn’t matter if it’s actually an item. For examples it could be just a “notice” that is displayed once.
Object composition gives you way more possibilities and removes the strict constraint that inheritance introduces. On top of that certain things can be implemented with interfaces. For example “pickable” is such a simple thing that you usually don’t need a seperate class for it. So you could have an interface “IPickable” that is implemented by a WorldItem component since usually every item in the world can be picked up.
There are many other possible interfaces like IUseable(for buttons in the world), IDamageable(can get hurt), IKillable(can be killed, might be relevant for score counting), IPlaceable(can be placed back into the world). Each interface or component would provide methods to perform that task. So the system can simply check if an object has a component with the “IDamageable” interface and if it has it, the system knows that this object can receive damage by calling the “ApplyDamage(amount, type)” method. What actually happens to the object is handled by the class that actually implemented the interface.