I did some work back in the early fragmented mod era towards fixing exactly that, by using name-based dynamic mappings in the save file. Since vanilla blocks were at their same numbers, it was compatible with vanilla. All mods got dynamic IDs, and I added a tag to each chunk that was a compressed form of the mapping (Vanilla{1=1,2=2,3=3} Buildcraft{1=4096,2=4097}...) Basically it didn't matter what mods you had or what order they loaded in, the world was always coherent. When loading, if a mapping corresponded to a mod you didn't have, it cloned an airblock to that ID.
I could start a world (with mods), place mod blocks, save it, remove the mods, load the world - the missing mod blocks looked and acted like air - save it again, re-add the mods, re-load and the mod blocks were back where they should be. It also worked when multiple mods claimed the same ID, by presenting blocks to them with the ID they expected, but maintaining a different ID in the in-memory storage.
It didn't have much overhead in runtime or storage, since the on-disk format was identical to vanilla with an extra compound tag that vanilla would ignore.