A ScriptableObject's Awake and OnEnable methods are called (in that order) as soon as the object is loaded.
This occurs when...
Loading a scene that contains a reference to the object (including in the editor)
Reloading recently referenced
ScriptableObjectsafter a code changeClicking on the object in the Project window or reference selector widget
That means if you're testing a scene that contains a reference to this ScriptableObject, it's already enabled before you click the Play Mode button.
To match the event flow you observe in a built game, Unity starts-up the object from scratch when entering Play Mode. (Imagine you were using your Awake or OnEnableOnEnable method to generate a random seed for a roguelike's procedural dungeon generation - if it didn't do this, you'd always get the same dungeon when testing in the editor)
But since the object was already started-up, in order to re-start it we have to shut it down first. That means calling OnDisable on it.
So the order of events you see when entering play mode is OnDisable -> Awake -> OnEnable, but only because we've narrowed our view too far. If we step back and look at the wider timeline we'll see something like this:
Launch Unity editor and open a scene referencing the object, or select the object in the inspector
Awake->OnEnableEnter Play Mode
->
OnDisable->Awake->OnEnableLoad a different scene that does not reference this object
->
OnDisable
So it is true that OnDisable occurs after OnEnable. Specifically, the OnDisable in (2) occurs after the OnEnable in (1), just like the OnDisable in (3) follows the OnEnable in (2).
Can I code all initialization code for the object in the
OnEnablemethod? Can I assume it will always execute before anyMonoBehaviourcan read it?
Yes. That is exactly the purpose of these methods.