I can provide some additional details for you because I’ve run into the same issue. What this turns out to be is that with a naïve implementation (it’s what I did the first time too) is that the ClassDefaultObject ends up getting registered to tick. The “real” instance of the subsystem is not actually ticking twice.
You can see the Epic solution to this in the UTickableWorldSubsystem (WorldSubsystem.h/cpp). It’s partly similar to your solution of not allowing ticking until the instance is initialized. The other part is that IsTickable always returns false when IsTemplate is true (meaning the instance is the CDO). It also checks IsTemplate as part of GetTickableTickType so that CDO’s return ::Never as the tick type.