diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index 2f4b30079..d05e77dff 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -102,6 +102,8 @@ g_type_value_table_peek
 g_type_ensure
 g_type_get_type_registration_serial
 g_type_get_instance_count
+g_type_type_init_enter
+g_type_type_init_leave
 
 G_DECLARE_FINAL_TYPE
 G_DECLARE_DERIVABLE_TYPE
diff --git a/gobject/gtype.c b/gobject/gtype.c
index b0f12f6c3..eed0ba64f 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -4901,3 +4901,50 @@ g_type_ensure (GType type)
     g_error ("can't happen");
 }
 
+/**
+ * g_type_type_init_enter:
+ * @location: (not nullable): location of a static initializable variable
+ *    containing 0
+ *
+ * Wrapper for g_once_init_enter(), also acquiring class initialization
+ * mutex, to avoid deadlocks when one type is initialized in two threads
+ * at the same time, as part of another type initialization.
+ *
+ * Returns: %TRUE if the initialization section should be entered,
+ *     %FALSE and blocks otherwise
+ *
+ * Since: 2.56
+ */
+gboolean
+g_type_type_init_enter (volatile gsize *location)
+{
+  g_rec_mutex_lock (&class_init_rec_mutex);
+  if (!g_once_init_enter (location))
+    {
+      g_rec_mutex_unlock (&class_init_rec_mutex);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ * g_type_type_init_leave:
+ * @location: (not nullable): location of a static initializable variable
+ *    containing 0
+ * @result: new non-0 value for *@value_location
+ *
+ * Counter part of g_type_type_init_enter(), wrapper for g_once_init_leave(),
+ * also releasing the class initialization mutex, previously acquired
+ * with g_type_type_init_enter(). This function should be used only if
+ * the previous call to g_type_type_init_enter() returned %TRUE.
+ *
+ * Since: 2.56
+ */
+void
+g_type_type_init_leave (volatile gsize *location,
+                        gsize           result)
+{
+  g_once_init_leave (location, result);
+  g_rec_mutex_unlock (&class_init_rec_mutex);
+}
diff --git a/gobject/gtype.h b/gobject/gtype.h
index 89c1bec16..2b0d4ae23 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -1324,6 +1324,17 @@ void      g_type_ensure                 (GType                       type);
 GLIB_AVAILABLE_IN_2_36
 guint     g_type_get_type_registration_serial (void);
 
+/* Macros used to simplify the below code, which is different
+ * when the client defines GLIB_VERSION_MAX_ALLOWED below 2.56,
+ * due to g_type_type_init_enter() and g_type_type_init_leave()
+ * being introduced in 2.56. */
+#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_56
+#define g_type_type_init_enter_func g_type_type_init_enter
+#define g_type_type_init_leave_func g_type_type_init_leave
+#else
+#define g_type_type_init_enter_func g_once_init_enter
+#define g_type_type_init_leave_func g_once_init_leave
+#endif
 
 /* --- GType boilerplate --- */
 /**
@@ -1707,7 +1718,7 @@ guint     g_type_get_type_registration_serial (void);
  * gtk_gadget_get_type (void)
  * {
  *   static volatile gsize g_define_type_id__volatile = 0;
- *   if (g_once_init_enter (&g_define_type_id__volatile))
+ *   if (g_type_type_init_enter (&g_define_type_id__volatile))
  *     {
  *       GType g_define_type_id =
  *         g_type_register_static_simple (GTK_TYPE_WIDGET,
@@ -1723,7 +1734,7 @@ guint     g_type_get_type_registration_serial (void);
  *         };
  *         g_type_add_interface_static (g_define_type_id, TYPE_GIZMO, &g_implement_interface_info);
  *       }
- *       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ *       g_type_type_init_leave (&g_define_type_id__volatile, g_define_type_id);
  *     }
  *   return g_define_type_id__volatile;
  * }
@@ -1968,7 +1979,7 @@ type_name##_get_type (void) \
 
 /* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */
 #define _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \
-  if (g_once_init_enter (&g_define_type_id__volatile))  \
+  if (g_type_type_init_enter_func (&g_define_type_id__volatile))  \
     { \
       GType g_define_type_id = \
         g_type_register_static_simple (TYPE_PARENT, \
@@ -1982,7 +1993,7 @@ type_name##_get_type (void) \
 #define _G_DEFINE_TYPE_EXTENDED_END()	\
         /* following custom code */	\
       }					\
-      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
+      g_type_type_init_leave_func (&g_define_type_id__volatile, g_define_type_id); \
     }					\
   return g_define_type_id__volatile;	\
 } /* closes type_name##_get_type() */
@@ -2002,7 +2013,7 @@ GType \
 type_name##_get_type (void) \
 { \
   static volatile gsize g_define_type_id__volatile = 0; \
-  if (g_once_init_enter (&g_define_type_id__volatile))  \
+  if (g_type_type_init_enter_func (&g_define_type_id__volatile))  \
     { \
       GType g_define_type_id = \
         g_type_register_static_simple (G_TYPE_INTERFACE, \
@@ -2018,7 +2029,7 @@ type_name##_get_type (void) \
 #define _G_DEFINE_INTERFACE_EXTENDED_END()	\
         /* following custom code */		\
       }						\
-      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
+      g_type_type_init_leave_func (&g_define_type_id__volatile, g_define_type_id); \
     }						\
   return g_define_type_id__volatile;			\
 } /* closes type_name##_get_type() */
@@ -2074,7 +2085,7 @@ GType \
 type_name##_get_type (void) \
 { \
   static volatile gsize g_define_type_id__volatile = 0; \
-  if (g_once_init_enter (&g_define_type_id__volatile))  \
+  if (g_type_type_init_enter_func (&g_define_type_id__volatile))  \
     { \
       GType (* _g_register_boxed) \
         (const gchar *, \
@@ -2099,7 +2110,7 @@ GType \
 type_name##_get_type (void) \
 { \
   static volatile gsize g_define_type_id__volatile = 0; \
-  if (g_once_init_enter (&g_define_type_id__volatile))  \
+  if (g_type_type_init_enter_func (&g_define_type_id__volatile))  \
     { \
       GType g_define_type_id = \
         g_boxed_type_register_static (g_intern_static_string (#TypeName), \
@@ -2140,7 +2151,7 @@ GType \
 type_name##_get_type (void) \
 { \
   static volatile gsize g_define_type_id__volatile = 0; \
-  if (g_once_init_enter (&g_define_type_id__volatile))  \
+  if (g_type_type_init_enter_func (&g_define_type_id__volatile))  \
     { \
       GType g_define_type_id = \
         g_pointer_type_register_static (g_intern_static_string (#TypeName)); \
@@ -2180,6 +2191,11 @@ void             g_type_remove_interface_check  (gpointer	         check_data,
 GLIB_AVAILABLE_IN_ALL
 GTypeValueTable* g_type_value_table_peek        (GType		     type);
 
+GLIB_AVAILABLE_IN_2_56
+gboolean         g_type_type_init_enter         (volatile gsize     *location);
+GLIB_AVAILABLE_IN_2_56
+void             g_type_type_init_leave         (volatile gsize     *location,
+                                                 gsize               result);
 
 /*< private >*/
 GLIB_AVAILABLE_IN_ALL
