Thanks Silverleaf, your direction was great.
I just wanted to make a final note here for future devs dealing with this situation. My solution was to serialize actors into a struct that also holds the class, transform, and actor name, following the direction outlined here: What is the best way to handle Saving/Loading an Array of Objects? - Programming & Scripting - Epic Developer Community Forums
That struct is inside a SaveGame object, and as long as it’s marked as a UProperty it will be saved to disk along with the SaveGame. On load (make sure it’s a fresh level start or restart as a property will not be serialized if it’s equal to its default value), I go through all of the saved structs and de-serialize over the matching actor in the world. For static actors, I find the world’s matching actor using FindObject:
FindObject<AActor>(WorldContextObject->GetWorld(), *(SavedActor.ActorName))
Dynamic actors like PlayerCharacter and GameState can’t use the FindObject method as their names change each time the level restarts - you will need to get these objects from something like UGameplayStatics.