With 2.35 Blender now offers a 'global undo' as well. It is called global, because it works outside of the temporal editing modes (like mesh editing or vertex paint) and restores on 'undo' the entire database of Blender.
For all undo operations you now can use CTRL + Z (undo) and SHIFT + CTRL + Z (redo) or CTRL + Y (redo). For Mac users you can replace CTRL with the Apple key too. In Edit Mode the old U and SHIFT + U keys work still though.
The hotkey ALT + U shows the current undo levels.
Note; The old CTRL + Z (recalculate shading drawmode) in the 3D window now is SHIFT + ALT + Z. This actually became a quite redundant option, since Shaded drawmode (SHIFT + Z) already is being recalculated in many situations.
Enable Global Undo with the setting in the User Menu (Info Window). This is set on by default. In the User Menu you can also set the amount of undo steps to store. The amount of required undo memory always is at least the size of the current .blend file, plus an average of about 2-5% of that per undo step.
Undo operations don't (re)store the UI or view settings - as typically is being saved in Blender files - this means that after making changes in the UI, not all undo/redo steps can be obviously visible in all circumstances.
Example: load new image in UV editor, undo, redo; the new image is back but the UV editor doesn't show it.
Most important to know: the EditMode undo stacks are separate from the 'Global undo' stack. This means that when you are in EditMode, you can only undo steps back to when you entered the mode. When you leave EditMode you can undo further, but this will skip EditModes entirely.
This situation is not a real design decision, but grown from the past - with only EditMode undo available.
Advantage however is that you can always - independent from global undo steps - enter an EditMode again and still have the full original undo stack available. Whether we stick to this, or fully unify the Undo is for a next release.
With actually the 'current file' being in memory, this can be saved quickly to disk too. That's now happening by default when you exit Blender, giving a "session recovery" file. You can load that file in the main File pulldown menu.
This feature will solve loss of work when accidentally quitting Blender.
All editors and Edit Modes in Blender have undo now, with exceptions listed below.
Typically an undo system is based on principles where all changes in the data are being tracked by for example 'history lists' (like script lines), or by wrapping all data-changes with separate functions that can construct an event list for what has changed.
Blender wasn't designed with an undo in mind. In the code it even violates quite common software architecture rules by accessing/changing data all over the code, without any abstraction layer inbetween to catch such changes.
Of course that approach has benefits too... especially in coding and execution speed.
However, what is possible in Blender is using a brute force approach - like the Blender 2.3x Mesh edit undo - where the full dataset that's being worked at is being stored and cached. With typical Meshes not being larger than half a megabyte in memory, not a system that will give noticable slowdown.
That method is still in Blender, and has been added for Curve, Surface, 3D Text, MetaBall and Lattice editing too.
With Blender saving and reading files incredible fast, tests were done to verify if this would give acceptable undo for the rest of Blender editing. Main problem is that this quickly becomes a scaling issue; with complex projects in Blender nowadays easily going to dozens of megabytes. Disk access also can become a bottleneck, where using memory is much faster.
The solution was found by streamlining and altering the core file saving routines.
When a Blender file is being saved, it already gathered fixed 'chunks' of minimum 50 kB, this to minimize disk and network overhead. These chunks now, for an 'undo save' can be copied to memory directly. That will result in a list of chunks that can be easily fed to the reading code for doing an 'undo'.

This image shows the situation in memory for the first 'undo push'. Note that chunks can each be of a different size.
When something in Blender changes, a 2nd buffer should be created. To prevent a series of buffers going into the 100s of megabytes, a simple compression mechanism was added...

While saving the data, each chunk is first being binary compared with the previous chunk. If it's equal it doesn't store (copy) the chunk but instead refers to the previous one.
By efficiently organizing the chunks, and by signalling to flush chunks when new 'library data types' are saved, the coherence of this system is pretty good. Here's for example what happens when adding a new Mesh object:

And because most of the changes in Blender - while editing - are very minimal, most of the undo changes only involve copying a single chunk:

Since many of the larger chunks in Blender (like vertex arrays) are not copied at all during this process, but only compared, this all happens with great efficiency.
Overhead of new memory allocations during undo-buffering also is minimized by the compression scheme.
Another crucial improvement was to do an undo-push after an editing command (instead of before, as in current mesh undo). This efficiently uses the small time intervals between user actions.
And last but not least; this systems gives on each 'undo level' a full available set of chunks which can be immediately read. Each undo level can be easily removed or merged with the previous one.
Timing tests have shown that this works interactive still with datasets of 20 MB, even on a 450 Mhz G4 system.
The system has matured and been tested for over 6 weeks, with lots of issues found and fixed. The undo system isn't fully finished yet however, with work to do on a couple of areas: