The current road world champion outsprinted Sacha Modolo (UAE Team Emirates) and Matteo Trentin (Quick-Step Floors) to take his career tally of victories in the race to 15.
Sagan (BORA-hansgrohe), showed he is in fine form ahead of the defence of his Tour de France Green Jersey when the race starts in Dusseldorf on 1 July.
“It was a very good day for us and once again I have to thank my teammates for their strong effort,” Sagan said. “
“We were practically the only ones to control the race today, so they did an excellent job.
“I’m happy for my second stage win this year, my fifteenth overall. The Tour de Suisse is a race I like, although it’s too early to talk about next year. I hope I can come back.”
The punchy 100km on Stage 8, made up of eight laps of a 12.5km circuit and featuring two climbs, was perfectly suited to Sagan's abilities.
Lasse Norman Hansen (Aqua Blue Sport), Jelle Wallays (Lotto Soudal), Jaco Venter (Dimension Data) and Nick Van der Lijke (Roompot-Nederlandse Loterij) were the first four riders allowed off the leash but were kept under watch on the high-speed stage.
The breakaway was caught on the last lap, with 12.5km to go, and six kilometres later Australian Michael Matthews (Sunweb) attempted a long-range strike but was chased down by Sagan’s Bora-Hansgrohe team-mate Marcus Burghardt.
As the peloton regrouped it was Fabio Felline (Trek-Segafredo) who launched the next attack but without success.
The final kilometre was led by Philippe Gilbert and Quick-Step Floors in the hopes of earning Trentin a stage win but they were denied by Sagan.
Simon Špilak (Katusha-Alpecin) leads the general classification, with a 52-second advantage on Damiano Caruso (BMC). Steven Kruijswijk (LottoNL-Jumbo) is in third at 1min 5sec.
The Tour de Suisse winner will be decided on the final stage 28.6km ITT, again held in Schaffhausen.