I like the 3rd option but I cannot see overridable equivalent, event or function on blueprint side. But I can imagine having BlueprintImplementable init function I could then invoke e.g. from PostInitializeComponents to keep it clean and organized.
The 2nd option (moving Super::BeginPlay at the end) might not be a good idea in my opinion. Technically speaking, I believe the parent class should not assume about implementation details in class that will inherit from it. Super::BeginPlay at the end may already change the state of the parent in a way the parent is not expecting.
I’ll try out PostInitializeComponents - thanks for pointing that out.