Observable timer sequence
Although you didn't explicitly ask this (and I should now, as I am you) it's worthwhile to first look at why the first piece of code doesn't work, and why the approach is ill-advised.

Observable.ToEnumerable() has a fundamental problem in that it doesn't (cannot) know when the consumer of the resulting IEnumerable is going to enumerate. As a result, it is forced to buffer all the values that the observable is producing, until the consumer is kind enough to fetch them. Essentially, this produces a hidden producer/consumer model involving two threads. If the consumer is "sufficiently fast", the overhead of this may not be noticeable, but it's always there. Whenever you find yourself using Observable.ToEnumerable(), you're probably doing something wrong.

The second approach, where we build an enumerable sequence of observables and then .Concat() works (and I can't see any potential problems with it in terms of multiple subscriptions or cancellation), but has more overhead than necessary in that it produces a separate Observable for every single point in time, with each of these producing a single value. This wouldn't be necessary if we had a single observable to produce the values in order, and that's essentially what the third piece of code achieves.

The third piece of code is a tad cryptic if you don't see what overload of .Generate() it's calling. We can make this clearer by adding the parameter names:

Observable.Generate(
  initialState: getScheduleTimes().GetEnumerator(), 
  condition: e =&gt; e.MoveNext(), 
  iterate: e =&gt; e, 
  resultSelector: e =&gt; e.Current, 
  timeSelector: e =&gt; e.Current
);


The timeSelector parameter is documented rather sparsely as "the time selector function to control the speed of values being produced each iteration". Paraphrasing the actual implementation and assuming an implicit scheduler, .Generate() produces an observable that does this:

var dueTime = default(DateTimeOffset);
bool first = true;
var state = initialState();
if (hasResult) {
    observer.OnNext(result);
}
if (first) {
    first = false;
} else {
    state = iterate(state);
}
hasResult = condition(state);
if (hasResult) {
    result = resultSelector(state);
    dueTime = timeSelector(state);
    scheduler.Schedule(dueTime, Generate(...));
} else {
    observer.OnCompleted();
}


In the actual implementation, scheduling the tail-recursive call is more involved than this. If we substitute in our actual arguments:

var enumerator = getScheduleTimes().GetEnumerator();
if (hasResult) {
    observer.OnNext(result);
}
if (first) {
    first = false;
} else {
    enumerator = enumerator;
}
hasResult = enumerator.MoveNext();
if (hasResult) {
    result = enumerator.Current;
    dueTime = enumerator.Current;
    scheduler.Schedule(dueTime, generate(...));
} else {
    observer.OnCompleted();
}


So this is almost like a regular enumeration, but with the twist that each value we produce is also used as the time at which it should be produced.

There's a slight niggle in that, unlike the foreach pattern, this application of .Generate() will not call IEnumerator.Dispose() like an enumeration is supposed to. In this case, that's not a problem since we're using an iterator and those always have do-nothing Dispose() implementations, but if you were getting the times from another source, you would need to dispose them. That's exactly what Observable.Using() is for. If we put this together in a little extension method that works like Observable.Timer(), but for more than one point in time:

public static class ObservableExtensions {
  public static IObservable&lt;DateTimeOffset&gt; Timers(
    IEnumerable&lt;DateTimeOffset&gt; sequence
  ) {
    return Timers(sequence, Scheduler.Default);
  }

  public static IObservable&lt;DateTimeOffset&gt; Timers(
    IEnumerable&lt;DateTimeOffset&gt; sequence,
    IScheduler scheduler
  ) {
    return Observable.Using(
      () =&gt; sequence.GetEnumerator(),
      e =&gt; Observable.Generate(
        initialState: e,
        condition: ee =&gt; ee.MoveNext(),
        iterate: ee =&gt; ee,
        resultSelector: ee =&gt; ee.Current,
        timeSelector: ee =&gt; ee.Current,
        scheduler: scheduler
      )
    );
  }
}


And this would be my preferred way of doing it: using an IEnumerable allows us to test the result of code that produces a schedule in a simple way, while providing an IScheduler overload still allows us to test observable sequences as a whole using the TestScheduler if we are so inclined.