I would recommend using TryGetValue instead of Contains() because when you use Contains() you are doing 2 lookups in the dictionary. If you use TryGetValue you can both check if it exists and get the value in one lookup.

if(state.TryGetValue(saveable.GetType().ToString(), out var value)) {

I’m actually not sure if there is a saving or not (unfortunately, Jetbrains decompiler stops on the declaration for the IDictionary methods, so I can’t see the implementation).
Either way, it does make the code tighter on the script end!