public function getProperty(string $property, bool $merge = false)
    {
        if (isset($this->propertyCache[$property])) {
            //Property merging and trait events are pretty slow
            return $this->propertyCache[$property];
        }

        $properties = $this->reflection->getDefaultProperties();
        $constants = $this->reflection->getConstants();

        if (isset($properties[$property])) {
            //Read from default value
            $value = $properties[$property];
        } elseif (isset($constants[strtoupper($property)])) {
            //Read from a constant
            $value = $constants[strtoupper($property)];
        } else {
            return null;
        }

        //Merge with parent value requested
        if ($merge && is_array($value) && !empty($parent = $this->parentReflection())) {
            $parentValue = $parent->getProperty($property, $merge);

            if (is_array($parentValue)) {
                //Class values prior to parent values
                $value = array_merge($parentValue, $value);
            }
        }

        if (!$this->reflection->isSubclassOf(SchematicEntity::class)) {
            return $value;
        }

        //To let traits apply schema changes
        return $this->propertyCache[$property] = call_user_func(
            [$this->getName(), 'describeProperty'], $this, $property, $value
        );
    }