I looked into different ways to re-architect the inheritence structure of the ~15 custom classes that needed to be persisted. Unfortunately it would require more time, effort and testing than the current project would allow.
The best solution (for now) was to create a new "lightweight" class (similar to DatasetName vs. Dataset). This lightweight class stores attributes common to each of those ~15 classes, including type and unique key values.
During IPersistStream_Save, a lightweight class is created for each instance of a custom class and filled up with the necessary information. Then during IPersistStream_Load the type and key value of each lightweight class object is used to make database calls via a SQL package. The returned values are then used to recreate the full custom classes.