Track both the abstraction the caller sees and the real object type that supplies overridden behavior.
Polymorphic code is easiest to misread when you look at only one type. The reference type tells you what operations are visible; the runtime object tells you which override actually runs.