I think you could use a valueAtTime() expression here.
You’d animate the first layer, and then you’d use an expression on the other layers to use the first layer’s animation, but offset in time.
Try this:
On your second layer, add this expression to the opacity property:
target = thisComp.layer("MyFirstLayer") ; // change MyFirstLayer to your first layer's name
target.opacity.valueAtTime( time - inPoint )
Then adjust the in-point of the second layer as needed for the timing that you need.
If that will work for you, you can apply that expression to all of the other layers by right-clicking the opacity of the second layer (that has the expression) and choose ‘copy expression only’.
Then select all of the other layers (except the first ‘target’ layer) and paste.
If needed, you can adjust the in-points of all the layers using the Animation > Keyframe Assistant > Sequence Layers menu option. Move the CTI to the in point of the first ‘target’ layer, select all of the layers and hit the left bracket key (‘[‘) to line them all up, then move the CTI to the last key frame of the animation and hit Option-] (right-bracket) or Alt-] (Windows) to trim all of the layers. Then choose Animation > Keyframe Assistant > Sequence Layers and choose ‘overlap’ and enter the amount of overlap. This would be the duration of the layers minus the amount of offset. EX: each layer is 3 seconds and you want an offset of .5 seconds, the overlap would be 3 – 0.5 = 2.5 seconds : )
That should sequence all 900 layers and each should fallow the first layer’s opacity animation. Now if you change the first layer’s animation curve, it will affect all 900 layers.