Only small part of the objects of the classes are used as keys in hash tables
I would argue that this is not a true statement. Many classes are often used as keys in hash tables - and object references themselves are very often used. Having the default implementation of GetHashCode exist in System.Object means that ANY object can be used as a key, without restrictions.
This seems much nicer than forcing a custom interface on objects, just to be able to hash them. You never know when you may need to use an object as the key in a hashed collection.
This is especially true when using things like HashSet<T>
- In this case, often, an object reference is used for tracking and uniqueness, not necessarily as a "key". Had hashing required a custom interface, many classes would become much less useful.