diff --git a/core/object/object.cpp b/core/object/object.cpp
index c324eab9bbd2..39cae7c5bd1d 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -195,14 +195,15 @@ bool Object::_predelete() {
 	_predelete_ok = 1;
 	notification(NOTIFICATION_PREDELETE, true);
 	if (_predelete_ok) {
-		_class_ptr = nullptr; //must restore so destructors can access class ptr correctly
+		_class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
 	}
 	return _predelete_ok;
 }
 
 void Object::_postinitialize() {
-	_class_ptr = _get_class_namev();
+	_class_name_ptr = _get_class_namev(); // Set the direct pointer, which is much faster to obtain, but can only happen after postinitialize.
 	_initialize_classv();
+	_class_name_ptr = nullptr; // May have been called from a constructor.
 	notification(NOTIFICATION_POSTINITIALIZE);
 }
 
diff --git a/core/object/object.h b/core/object/object.h
index 5ec69a371b0b..4226b5e67b9e 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -376,7 +376,6 @@ public:                                                             \
 #define GDCLASS(m_class, m_inherits)                                                                                                             \
 private:                                                                                                                                         \
 	void operator=(const m_class &p_rval) {}                                                                                                     \
-	mutable StringName _class_name;                                                                                                              \
 	friend class ::ClassDB;                                                                                                                      \
                                                                                                                                                  \
 public:                                                                                                                                          \
@@ -388,13 +387,11 @@ public:
 		return String(#m_class);                                                                                                                 \
 	}                                                                                                                                            \
 	virtual const StringName *_get_class_namev() const override {                                                                                \
-		if (_get_extension()) {                                                                                                                  \
-			return &_get_extension()->class_name;                                                                                                \
-		}                                                                                                                                        \
-		if (!_class_name) {                                                                                                                      \
-			_class_name = get_class_static();                                                                                                    \
+		static StringName _class_name_static;                                                                                                    \
+		if (unlikely(!_class_name_static)) {                                                                                                     \
+			StringName::assign_static_unique_class_name(&_class_name_static, #m_class);                                                          \
 		}                                                                                                                                        \
-		return &_class_name;                                                                                                                     \
+		return &_class_name_static;                                                                                                              \
 	}                                                                                                                                            \
 	static _FORCE_INLINE_ void *get_class_ptr_static() {                                                                                         \
 		static int ptr;                                                                                                                          \
@@ -614,8 +611,7 @@ class Object {
 	Variant script; // Reference does not exist yet, store it in a Variant.
 	HashMap<StringName, Variant> metadata;
 	HashMap<StringName, Variant *> metadata_properties;
-	mutable StringName _class_name;
-	mutable const StringName *_class_ptr = nullptr;
+	mutable const StringName *_class_name_ptr = nullptr;
 
 	void _add_user_signal(const String &p_name, const Array &p_args = Array());
 	bool _has_user_signal(const StringName &p_name) const;
@@ -714,10 +710,11 @@ class Object {
 	Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
 
 	virtual const StringName *_get_class_namev() const {
-		if (!_class_name) {
-			_class_name = get_class_static();
+		static StringName _class_name_static;
+		if (unlikely(!_class_name_static)) {
+			StringName::assign_static_unique_class_name(&_class_name_static, "Object");
 		}
-		return &_class_name;
+		return &_class_name_static;
 	}
 
 	Vector<StringName> _get_meta_list_bind() const;
@@ -788,13 +785,16 @@ class Object {
 
 	_FORCE_INLINE_ const StringName &get_class_name() const {
 		if (_extension) {
+			// Can't put inside the unlikely as constructor can run it
 			return _extension->class_name;
 		}
-		if (!_class_ptr) {
+
+		if (unlikely(!_class_name_ptr)) {
+			// While class is initializing / deinitializing, constructors and destructurs
+			// need access to the proper class at the proper stage.
 			return *_get_class_namev();
-		} else {
-			return *_class_ptr;
 		}
+		return *_class_name_ptr;
 	}
 
 	/* IAPI */
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index df9b6b3f1aad..6099fea13f5d 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -201,6 +201,14 @@ StringName::StringName(const StringName &p_name) {
 	}
 }
 
+void StringName::assign_static_unique_class_name(StringName *ptr, const char *p_name) {
+	mutex.lock();
+	if (*ptr == StringName()) {
+		*ptr = StringName(p_name, true);
+	}
+	mutex.unlock();
+}
+
 StringName::StringName(const char *p_name, bool p_static) {
 	_data = nullptr;
 
diff --git a/core/string/string_name.h b/core/string/string_name.h
index 177e82896d33..07abc781a287 100644
--- a/core/string/string_name.h
+++ b/core/string/string_name.h
@@ -177,6 +177,8 @@ class StringName {
 	StringName(const String &p_name, bool p_static = false);
 	StringName(const StaticCString &p_static_string, bool p_static = false);
 	StringName() {}
+
+	static void assign_static_unique_class_name(StringName *ptr, const char *p_name);
 	_FORCE_INLINE_ ~StringName() {
 		if (likely(configured) && _data) { //only free if configured
 			unref();