Prefab seems to break polymorphism

Instantiation seems to change which method is called (base class or derived class)
I’ll admit I’m no expert in C# polymorphism, but can someone tell me what’s going on here?
It seems the uninstantiated prefab will only call the base class methods, but the instantiated game object will call the derived class method.


using UnityEngine;

public abstract class ParentScript : MonoBehaviour {
    virtual internal string firstName {get; set;} = "Mother";
    void Start() {
        Debug.Log("Start: " + firstName);


using UnityEngine;

public class ChildScript : ParentScript {
    override internal string firstName {get; set;} = "Daughter";


using UnityEngine;

public class CreatorScript : MonoBehaviour {
    // An empty gameobject with only a ChildScript component
    public GameObject prefab;

    void Start() {
        ParentScript parentScript = prefab.GetComponent<ParentScript>();
        Debug.Log("Before Instantiation (pulled as parent): " + parentScript.firstName);

        ChildScript childScript = prefab.GetComponent<ChildScript>();
        Debug.Log("Before Instantiation (pulled as child): " + childScript.firstName);

        ChildScript asChildScript = (parentScript as ChildScript);
        Debug.Log("Before Instantiation (as child): " + asChildScript.firstName);

        ChildScript castChildScript = (ChildScript) parentScript;
        Debug.Log("Before Instantiation (cast as child): " + castChildScript.firstName);

        GameObject p = Instantiate(prefab,, Quaternion.identity);
        Debug.Log("After Instantiation (prefab): " + parentScript.firstName);

        ParentScript instantiatedParentScript = p.GetComponent<ParentScript>();
        Debug.Log("After Instantiation (instantiated - pulled as parent): " + instantiatedParentScript.firstName);
        ChildScript instantiatedChildScript = p.GetComponent<ChildScript>();
        Debug.Log("After Instantiation (instantiated - pulled as child): " + instantiatedChildScript.firstName);

Console Output

Before Instantiation (pulled as parent): Mother
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:9)

Before Instantiation (pulled as child): Mother
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:12)

Before Instantiation (as child): Mother
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:15)

Before Instantiation (cast as child): Mother
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:18)

After Instantiation (prefab): Mother
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:21)

After Instantiation (instantiated - pulled as parent): Daughter
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:25)

After Instantiation (instantiated - pulled as child): Daughter
UnityEngine.Debug:Log (object)
CreatorScript:Start () (at Assets/CreatorScript.cs:27)

Start: Daughter
UnityEngine.Debug:Log (object)
ParentScript:Start () (at Assets/ParentScript.cs:7)

Note: The scene is just a single empty game object with a CreatorScript component
Note: GetType() for any of these will return ChildScript

For what it is worth, this is the simplest example I could create, but in my real project, I have an uninstantiated prefab where I know it’s script’s base class, but not the derived class. So I can get the script with
var script = GetComponent<BaseClass>() but when I go to call any method, it is useless as it only calls the base class method. Even explicitly casting to the child class doesn’t seem to help.

(and c# won’t allow the kind of dynamic typing that would normally get one out of this situation)

(If anyone cares, in the real project, the base class has many properties of different types, and each derived class will only override a handful, so dictionaries or abstract methods or other solutions I would normally go with wont help)

That is normal behaviour for C#, if you want to be able to call child methods from a base class reference you need to make a virtual method in the base class and then override it in the child class.