Disclaimer: Super (over)simplistic intuitive explanation, without getting into proper technical detail.
I will start by pointing out that downcasting may be possible in special cases; specifically, on a "parent" object that was itself created by upcasting a "child" object. Hopefully the reason for this will be clear in a sec.
Say you have a Parent object with field x.
And a Child object which extends this with another field y.
When you instantiate a Parent object normally, java allocates enough memory to hold x.
When you instantiate a Child object, java allocates enough memory to hold both x and y.
When you upcast a Child object onto a Parent one, the memory layout doesn't change; java simply ignores the memory bit that was reserved for y, and treates all calls to this object as if it only contained x.
But if you were to attempt to downcast a Parent object into a Child one, you would essentially be missing the bit that refers to y in the object's memory footprint. Since the intent is one of 'casting' rather than "copying the object somewhere else", casting in this case is not allowed.
In the case the the Parent object was originally obtained by upcasting a Child object, it is then possible to downcast it back into a Child object; java treats this as a special case, since the memory layout would allow it.
This is also the reason that downcasting is treated as a runtime bug, rather than a compilation one.
PS. Note that the corollary from this is that when one upcasts at instantiation, while this is treated as a Parent object in the code, an entire Child object is stored in memory -- which is why a successful downcast back to a Child object can reoccur at any time.