Even had he not won, Thomas would have taken the yellow jersey with a good finish as Greg Van Avermaet slumped in the second half of the race.
The Briton completed the 108.5km stage in 3:29:36, beating Team Sunweb’s Tom Dumoulin into second place, with teammate Chris Froome third across the line.
Thomas leads the general classification with a time of 44:06:16, with Froome almost one-and-a-half-minutes behind.
Several kilometres into the race the quartet of Warren Barguil, Romain Sicard, Damiano Caruso and Damiano Caruso broke away and gradually extended their lead as the contest wore on.
Tejay van Garderen and Julian Alaphilippe later joined them up front, as the six established a 30-second lead over a 38-man chasing bunch and almost four minutes over the peloton.
With approximately 85km remaining, Barguil set a fast pace at the head of affairs but, being almost 12 minutes down on the general classification, posed no threat to the other race contenders.
A few more riders from the chasing group merged with the breakaway further up the climb, as the peloton dropped to nearly five minutes behind.
Barguil, Alaphilippe and Thomas De Gendt went clear just before the Col du Pre, a 12.6km climb with a 7.7 per cent ascent. The gap to the peloton by that point had increased to almost six minutes.
The chasing group were just 20 seconds behind the leading trio at the 60km mark, as the peloton trailed six minutes behind.
Several kilometres later the chasers caught up with the leaders, as Pierre Rolland pinned himself near the front. Movistar began making moves from within the peloton with 56km left.
Over the next six kilometres, Fortuneo-Samsic forced their way to the front of the breakaway as the group was reduced to 13 riders. The breakaway group was four minutes and 11 seconds ahead of the chasers and six-and-a-half minutes in front of the peloton.
Yellow jersey-holder Van Avermaet fell eight minutes behind with just over 40km left.
Fortuneo-Samsic – comprising Barguil, Élie Gesbert and Amaël Moinard – continued to control the break, with Barguil looking to be in a strong position to take the stage spoils.
Thomas, who was second on the GC before the stage, was the virtual leader with less than 30km to go, as Van Avermaet fell 10 minutes behind.
The breakaway group dwindled to five riders as they approached La Rosière, the final 17.6km long climb with a 5.8 per cent ascent. Barguil and Moinard stayed at the front.
Mikel Nieve attacked in the break and went ahead, as Barguil eventually fell behind with 8km to go. Thomas was with Tom Dumoulin and Damiano Caruso in the chase.
Nieve held the lead with just less than 5km left, the peloton one-and-a-half minutes behind. Chris Froome and Daniel Martin broke clear from the peloton shortly after that point.
Dramatically, Thomas surged past Nieve with just 300m to go to take the stage win and with it the yellow jersey. Froome swept through to take third behind Dumoulin, as Nieve tired on the final ascending metres.
“It was unreal and I didn’t expect it at all,” Thomas said of his victory afterwards.
“We were low on numbers so it was more instinct when I went. it was so that we didn’t get caught out and be forced to ride.
“I got a little gap and then Chris was able to follow the other guys.
“I committed and got across to [Tom] Dumoulin and was able to sit on because Chris was coming across.
“I could see Frosty [Mikel Nieve], and it was a shame, but I had to go for that win. It was super nice.”