The basic difference is when the value of the generated column is computed. For GENERATED AS ... VIRTUAL the computation is done when the row is retrieved so the value does not need to be stored in the row. For GENERATED AS ... STORED the computation is done each time the row is stored or updated and therefore the result of that computation must be stored in the row for subsequent retrieval. This is perhaps the simplest way to describe the distinction.