diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp
index 11640ec94..52a269873 100644
--- a/src/dobjtype.cpp
+++ b/src/dobjtype.cpp
@@ -3298,6 +3298,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
 				// see if we can reuse the existing class. This is only possible if the inheritance is identical. Otherwise it needs to be replaced.
 				if (this == existclass->ParentClass)
 				{
+					existclass->ObjectFlags &= OF_Transient;
 					return existclass;
 				}
 			}
diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp
index 66832c21c..5b03d4a60 100644
--- a/src/g_shared/a_artifacts.cpp
+++ b/src/g_shared/a_artifacts.cpp
@@ -1910,13 +1910,10 @@ void APowerMorph::InitEffect( )
 {
 	Super::InitEffect();
 
-	if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None)
+	if (Owner != nullptr && Owner->player != nullptr && PlayerClass != nullptr)
 	{
 		player_t *realplayer = Owner->player;	// Remember the identity of the player
-		PClassActor *morph_flash = PClass::FindActor(MorphFlash);
-		PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash);
-		PClassPlayerPawn *player_class = dyn_cast<PClassPlayerPawn>(PClass::FindClass (PlayerClass));
-		if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash))
+		if (P_MorphPlayer(realplayer, realplayer, PlayerClass, -1/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash))
 		{
 			Owner = realplayer->mo;				// Replace the new owner in our owner; safe because we are not attached to anything yet
 			ItemFlags |= IF_CREATECOPYMOVED;	// Let the caller know the "real" owner has changed (to the morphed actor)
@@ -1960,7 +1957,7 @@ void APowerMorph::EndEffect( )
 	}
 
 	// Unmorph if possible
-	if (!bNoCallUndoMorph)
+	if (!bInUndoMorph)
 	{
 		int savedMorphTics = Player->morphTics;
 		P_UndoPlayerMorph (Player, Player, 0, !!(Player->MorphStyle & MORPH_UNDOALWAYS));
diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h
index 163094d32..bd7e86323 100644
--- a/src/g_shared/a_artifacts.h
+++ b/src/g_shared/a_artifacts.h
@@ -280,13 +280,14 @@ class APowerMorph : public APowerup
 public:
 	
 	virtual void Serialize(FSerializer &arc);
-	void SetNoCallUndoMorph() { bNoCallUndoMorph = true; }
+	void SetNoCallUndoMorph() { bInUndoMorph = true; }
 
 	// Variables
-	FNameNoInit	PlayerClass, MorphFlash, UnMorphFlash;
+	PClassPlayerPawn *PlayerClass;
+	PClassActor *MorphFlash, *UnMorphFlash;
 	int MorphStyle;
 	player_t *Player;
-	bool bNoCallUndoMorph;	// Because P_UndoPlayerMorph() can call EndEffect recursively
+	bool bInUndoMorph;	// Because P_UndoPlayerMorph() can call EndEffect recursively
 
 protected:
 	void InitEffect ();
diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp
index 506f18b2f..49ea525bb 100644
--- a/src/g_shared/a_morph.cpp
+++ b/src/g_shared/a_morph.cpp
@@ -620,17 +620,13 @@ IMPLEMENT_CLASS(AMorphProjectile, false, false, false, false)
 
 int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype)
 {
-	PClassActor *morph_flash = PClass::FindActor(MorphFlash);
-	PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash);
 	if (target->player)
 	{
-		PClassPlayerPawn *player_class = dyn_cast<PClassPlayerPawn>(PClass::FindClass(PlayerClass));
-		P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash);
+		P_MorphPlayer (NULL, target->player, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
 	}
 	else
 	{
-		PClassActor *monster_class = PClass::FindActor(MonsterClass);
-		P_MorphMonster (target, monster_class, Duration, MorphStyle, morph_flash, unmorph_flash);
+		P_MorphMonster (target, MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
 	}
 	return -1;
 }
diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h
index 65f9d90b6..6911c6688 100644
--- a/src/g_shared/a_sharedglobal.h
+++ b/src/g_shared/a_sharedglobal.h
@@ -192,7 +192,8 @@ public:
 	
 	void Serialize(FSerializer &arc);
 
-	FNameNoInit	PlayerClass, MonsterClass, MorphFlash, UnMorphFlash;
+	PClassPlayerPawn *PlayerClass;
+	PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash;
 	int Duration, MorphStyle;
 };
 
diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp
index 9dcf3a16f..d6c53dd8d 100644
--- a/src/scripting/thingdef.cpp
+++ b/src/scripting/thingdef.cpp
@@ -68,6 +68,7 @@
 
 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
 void InitThingdef();
+TArray<PClassActor **> OptionalClassPtrs;
 
 // STATIC FUNCTION PROTOTYPES --------------------------------------------
 PClassActor *QuestItemClasses[31];
@@ -390,8 +391,21 @@ void LoadActors ()
 	{
 		if (ti->Size == TentativeClass)
 		{
-			Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars());
-			FScriptPosition::ErrorCounter++;
+			if (ti->ObjectFlags & OF_Transient)
+			{
+				Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars());
+				FScriptPosition::WarnCounter++;
+				DObject::StaticPointerSubstitution(ti, nullptr);
+				for (auto op : OptionalClassPtrs)
+				{
+					if (*op == ti) *op = nullptr;
+				}
+			}
+			else
+			{
+				Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars());
+				FScriptPosition::ErrorCounter++;
+			}
 			continue;
 		}
 
@@ -431,4 +445,6 @@ void LoadActors ()
 		QuestItemClasses[i] = PClass::FindActor(fmt);
 	}
 	StateSourceLines.Clear();
+	OptionalClassPtrs.Clear();
+	OptionalClassPtrs.ShrinkToFit();
 }
diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp
index 7faab937b..8968dc1d6 100644
--- a/src/scripting/thingdef_properties.cpp
+++ b/src/scripting/thingdef_properties.cpp
@@ -71,13 +71,14 @@
 #include "r_data/colormaps.h"
 #include "vmbuilder.h"
 
+extern TArray<PClassActor **> OptionalClassPtrs;
 
 //==========================================================================
 //
 // Gets a class pointer and performs an error check for correct type
 //
 //==========================================================================
-static PClassActor *FindClassTentative(const char *name, PClass *ancestor)
+static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool optional = false)
 {
 	// "" and "none" mean 'no class'
 	if (name == NULL || *name == 0 || !stricmp(name, "none"))
@@ -91,23 +92,27 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor)
 	{
 		I_Error("%s does not inherit from %s\n", name, ancestor->TypeName.GetChars());
 	}
+	if (cls->Size == TentativeClass && optional)
+	{
+		cls->ObjectFlags |= OF_Transient;	// since this flag has no meaning in class types, let's use it for marking the type optional.
+	}
 	return static_cast<PClassActor *>(cls);
 }
-static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name)
+static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false)
 {
-	return static_cast<AAmmo::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AAmmo)));
+	return static_cast<AAmmo::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional));
 }
-static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name)
+static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false)
 {
-	return static_cast<AWeapon::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AWeapon)));
+	return static_cast<AWeapon::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AWeapon), optional));
 }
-static APowerup::MetaClass *FindClassTentativePowerup(const char *name)
+static APowerup::MetaClass *FindClassTentativePowerup(const char *name, bool optional = false)
 {
-	return static_cast<APowerup::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APowerup)));
+	return static_cast<APowerup::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APowerup), optional));
 }
-static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name)
+static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name, bool optional = false)
 {
-	return static_cast<APlayerPawn::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn)));
+	return static_cast<APlayerPawn::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn), optional));
 }
 
 //==========================================================================
@@ -2984,21 +2989,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn)
 }
 
 //==========================================================================
-//
+// (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
 DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->PlayerClass = FName(str);
+	defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass);
 }
 
 //==========================================================================
-//
+// (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
 DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->MonsterClass = FName(str);
+	defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MonsterClass);
 }
 
 //==========================================================================
@@ -3020,12 +3027,13 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile)
 }
 
 //==========================================================================
-//
+// (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
 DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->MorphFlash = FName(str);
+	defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash);
 }
 
 //==========================================================================
@@ -3034,16 +3042,18 @@ DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile)
 DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->UnMorphFlash = FName(str);
+	defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash);
 }
 
 //==========================================================================
-//
+// (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
 DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->PlayerClass = FName(str);
+	defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass);
 }
 
 //==========================================================================
@@ -3056,21 +3066,23 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph)
 }
 
 //==========================================================================
-//
+// (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
 DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->MorphFlash = FName(str);
+	defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash);
 }
 
 //==========================================================================
-//
+// (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
 DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->UnMorphFlash = FName(str);
+	defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash);
 }