I have a suggestion, using the dynamic pointer of an instance to its own class: @constructor
In this example, the cache is initialized at first instance creation, and populated in the constructor itself.
class Animal
# is is just here to distinguish instances
id: null
constructor:(@id) ->
# @constructor aims at the current class: Animal or the relevant subclass
# init the cache if it does not exists yet
@constructor._cache = {} unless @constructor._cache?
# now populates the cache with the created instance.
@constructor._cache[@id] = @
class Dog extends Animal
# no need to override anything. But if you wish to, don't forget to call super().
# creates some instances
bart = new Animal 1
lucy = new Dog 1
rob = new Dog 2
console.log "animals:", Animal._cache
# prints: Object {1=Animal}
console.log "dogs:", Dog._cache
# prints: Object {1=Dog, 2=Dog}
see this fiddle (results on console)