The following both over-simplifies and treats one possible implementation as fact, but should suffice to have a working mental model.
When calling code "knows about" a class it knows the following things:
Fields can be accessed at a particular offset from the object's location. So for example if an object is at address 120, and has two integer fields, then it might be able to access one them at address 124. If another object of the same type was at address 140, the equivalent field would be at 144.
Non-virtual methods (and properties can be considered syntactic sugar on one or two methods) are functions at a particular address that take a reference to the object you are calling on (this from within the method) and the other parameters of that function.
Virtual methods are like the above, but their address can be found by looking at a particular offset within a table associated with the class, the address of which will also be a particular offset from the address of the class.
In this, Kid has a table of methods that is a superset of that of Parent (it could add more methods), and which has the same function address for those methods it didn't over-ride (calling Equals on it uses the same function as calling Equals on a Parent), but a different address for those it does over-ride (Print() in this case).
Hence if you have a Kid then whether you have it through a Parent reference or a Kid reference, calling Print() will look to the same table, look up the location of the Print() method, and call it.
In the case of Child, there is new used on the Print method. This tells the compiler that we specifically want a different table. Hence, if we call Print() via a Child reference, it looks up the Child-specific table, and calls the method it finds. If however we call it via a Kid or Parent reference, then we don't even know that there is a Child-specific table we could be using and we look up the function in the table we know Kid and Parent have respectively, and call the function found (that defined in Kid).
As a rule, new is to be avoided. It's use is in two places:
One is backwards compatibility. If for example Child had a Name property, and then later on the code for Parent was changed so that it too had a Name property, we've a conflict. Since Child's Name isn't an override, it gets treated as if it had new but gives us a warning, as this is the only way code using the old way of things and code that knows about the new Name on Parent can co-exist. If we ever come back to re-compile Child we should probably either refactor so it doesn't have its own Name (if that on Parent does what we want), refactor so it is an override, refactor to something completely different, or add new to indicate that this is how we want things to be despite it being less than ideal.
The other is when new allows for a more specific form of the same behaviour that the base class' method allows, but is logically compatible (so users don't get surprised). This latter should go in the semi-advanced techniques box and not be done lightly. It should also be commented as such, because most of the time seeing new means your dealing with something that is at best a compromise and should probably be improved.
(Aside: am I the only person who thought of tabloid newspapers upon seeing Kids having Children?)